111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert/* Copyright (c) 2015-2016 The Khronos Group Inc.
211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Copyright (c) 2015-2016 Valve Corporation
311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Copyright (c) 2015-2016 LunarG, Inc.
411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Copyright (C) 2015-2016 Google Inc.
511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert *
611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Licensed under the Apache License, Version 2.0 (the "License");
711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * you may not use this file except in compliance with the License.
811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * You may obtain a copy of the License at
911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert *
1011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert *     http://www.apache.org/licenses/LICENSE-2.0
1111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert *
1211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Unless required by applicable law or agreed to in writing, software
1311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * distributed under the License is distributed on an "AS IS" BASIS,
1411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * See the License for the specific language governing permissions and
1611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * limitations under the License.
1711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert *
1811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Author: Cody Northrop <cnorthrop@google.com>
1911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Author: Michael Lentine <mlentine@google.com>
2011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Author: Tobin Ehlis <tobine@google.com>
2111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Author: Chia-I Wu <olv@google.com>
2211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Author: Chris Forbes <chrisf@ijw.co.nz>
2311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Author: Mark Lobodzinski <mark@lunarg.com>
2411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Author: Ian Elliott <ianelliott@google.com>
2511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert */
2611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
2711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Allow use of STL min and max functions in Windows
2811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#define NOMINMAX
2911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
3011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Turn on mem_tracker merged code
3111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#define MTMERGESOURCE 1
3211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
3311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include <SPIRV/spirv.hpp>
3411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include <algorithm>
3511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include <assert.h>
3611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include <iostream>
3711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include <list>
3811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include <map>
3911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include <mutex>
4011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include <set>
4111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include <stdio.h>
4211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include <stdlib.h>
4311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include <string.h>
4411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include <string>
4511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include <tuple>
4611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
4711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include "vk_loader_platform.h"
4811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include "vk_dispatch_table_helper.h"
4911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include "vk_struct_string_helper_cpp.h"
5011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#if defined(__GNUC__)
5111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#pragma GCC diagnostic ignored "-Wwrite-strings"
5211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#endif
5311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#if defined(__GNUC__)
5411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#pragma GCC diagnostic warning "-Wwrite-strings"
5511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#endif
5611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include "vk_struct_size_helper.h"
5711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include "core_validation.h"
5811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include "vk_layer_table.h"
5911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include "vk_layer_data.h"
6011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include "vk_layer_extension_utils.h"
6111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include "vk_layer_utils.h"
6211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include "spirv-tools/libspirv.h"
6311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
6411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#if defined __ANDROID__
6511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include <android/log.h>
6611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#define LOGCONSOLE(...) ((void)__android_log_print(ANDROID_LOG_INFO, "DS", __VA_ARGS__))
6711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#else
6811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#define LOGCONSOLE(...)                                                                                                            \
6911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    {                                                                                                                              \
7011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        printf(__VA_ARGS__);                                                                                                       \
7111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        printf("\n");                                                                                                              \
7211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
7311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#endif
7411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
7511cd02dfb91661c65134cac258cf5924270e9d2Dan Albertusing namespace std;
7611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
7711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// TODO : CB really needs it's own class and files so this is just temp code until that happens
7811cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertGLOBAL_CB_NODE::~GLOBAL_CB_NODE() {
7911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i=0; i<VK_PIPELINE_BIND_POINT_RANGE_SIZE; ++i) {
8011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Make sure that no sets hold onto deleted CB binding
8111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (auto set : lastBound[i].uniqueBoundSets) {
8211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            set->RemoveBoundCommandBuffer(this);
8311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
8411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
8511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
8611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
8711cd02dfb91661c65134cac258cf5924270e9d2Dan Albertnamespace core_validation {
8811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
8911cd02dfb91661c65134cac258cf5924270e9d2Dan Albertusing std::unordered_map;
9011cd02dfb91661c65134cac258cf5924270e9d2Dan Albertusing std::unordered_set;
9111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
9211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// WSI Image Objects bypass usual Image Object creation methods.  A special Memory
9311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Object value will be used to identify them internally.
9411cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic const VkDeviceMemory MEMTRACKER_SWAP_CHAIN_IMAGE_KEY = (VkDeviceMemory)(-1);
9511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
9611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Track command pools and their command buffers
9711cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstruct CMD_POOL_INFO {
9811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkCommandPoolCreateFlags createFlags;
9911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    uint32_t queueFamilyIndex;
10011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    list<VkCommandBuffer> commandBuffers; // list container of cmd buffers allocated from this pool
10111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert};
10211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
10311cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstruct devExts {
10411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool wsi_enabled;
10511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    unordered_map<VkSwapchainKHR, SWAPCHAIN_NODE *> swapchainMap;
10611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    unordered_map<VkImage, VkSwapchainKHR> imageToSwapchainMap;
10711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert};
10811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
10911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// fwd decls
11011cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstruct shader_module;
11111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
11211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// TODO : Split this into separate structs for instance and device level data?
11311cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstruct layer_data {
11411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkInstance instance;
11511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
11611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    debug_report_data *report_data;
11711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::vector<VkDebugReportCallbackEXT> logging_callback;
11811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkLayerDispatchTable *device_dispatch_table;
11911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkLayerInstanceDispatchTable *instance_dispatch_table;
12011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
12111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    devExts device_extensions;
12211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    unordered_set<VkQueue> queues;  // all queues under given device
12311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Global set of all cmdBuffers that are inFlight on this device
12411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    unordered_set<VkCommandBuffer> globalInFlightCmdBuffers;
12511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Layer specific data
12611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    unordered_map<VkSampler, unique_ptr<SAMPLER_NODE>> samplerMap;
12711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    unordered_map<VkImageView, VkImageViewCreateInfo> imageViewMap;
12811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    unordered_map<VkImage, IMAGE_NODE> imageMap;
12911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    unordered_map<VkBufferView, VkBufferViewCreateInfo> bufferViewMap;
13011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    unordered_map<VkBuffer, BUFFER_NODE> bufferMap;
13111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    unordered_map<VkPipeline, PIPELINE_NODE *> pipelineMap;
13211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    unordered_map<VkCommandPool, CMD_POOL_INFO> commandPoolMap;
13311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    unordered_map<VkDescriptorPool, DESCRIPTOR_POOL_NODE *> descriptorPoolMap;
13411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    unordered_map<VkDescriptorSet, cvdescriptorset::DescriptorSet *> setMap;
13511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    unordered_map<VkDescriptorSetLayout, cvdescriptorset::DescriptorSetLayout *> descriptorSetLayoutMap;
13611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    unordered_map<VkPipelineLayout, PIPELINE_LAYOUT_NODE> pipelineLayoutMap;
13711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    unordered_map<VkDeviceMemory, DEVICE_MEM_INFO> memObjMap;
13811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    unordered_map<VkFence, FENCE_NODE> fenceMap;
13911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    unordered_map<VkQueue, QUEUE_NODE> queueMap;
14011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    unordered_map<VkEvent, EVENT_NODE> eventMap;
14111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    unordered_map<QueryObject, bool> queryToStateMap;
14211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    unordered_map<VkQueryPool, QUERY_POOL_NODE> queryPoolMap;
14311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    unordered_map<VkSemaphore, SEMAPHORE_NODE> semaphoreMap;
14411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    unordered_map<VkCommandBuffer, GLOBAL_CB_NODE *> commandBufferMap;
14511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    unordered_map<VkFramebuffer, FRAMEBUFFER_NODE> frameBufferMap;
14611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    unordered_map<VkImage, vector<ImageSubresourcePair>> imageSubresourceMap;
14711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> imageLayoutMap;
14811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    unordered_map<VkRenderPass, RENDER_PASS_NODE *> renderPassMap;
14911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    unordered_map<VkShaderModule, unique_ptr<shader_module>> shaderModuleMap;
15011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkDevice device;
15111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
15211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Device specific data
15311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    PHYS_DEV_PROPERTIES_NODE phys_dev_properties;
15411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkPhysicalDeviceMemoryProperties phys_dev_mem_props;
15511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
15611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data()
15711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        : report_data(nullptr), device_dispatch_table(nullptr), instance_dispatch_table(nullptr), device_extensions(),
15811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert          device(VK_NULL_HANDLE), phys_dev_properties{}, phys_dev_mem_props{} {};
15911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert};
16011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
16111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// TODO : Do we need to guard access to layer_data_map w/ lock?
16211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic unordered_map<void *, layer_data *> layer_data_map;
16311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
16411cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic const VkLayerProperties global_layer = {
16511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    "VK_LAYER_LUNARG_core_validation", VK_LAYER_API_VERSION, 1, "LunarG Validation Layer",
16611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert};
16711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
16811cd02dfb91661c65134cac258cf5924270e9d2Dan Alberttemplate <class TCreateInfo> void ValidateLayerOrdering(const TCreateInfo &createInfo) {
16911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool foundLayer = false;
17011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < createInfo.enabledLayerCount; ++i) {
17111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!strcmp(createInfo.ppEnabledLayerNames[i], global_layer.layerName)) {
17211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            foundLayer = true;
17311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
17411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // This has to be logged to console as we don't have a callback at this point.
17511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!foundLayer && !strcmp(createInfo.ppEnabledLayerNames[0], "VK_LAYER_GOOGLE_unique_objects")) {
17611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            LOGCONSOLE("Cannot activate layer VK_LAYER_GOOGLE_unique_objects prior to activating %s.",
17711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                       global_layer.layerName);
17811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
17911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
18011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
18111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
18211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Code imported from shader_checker
18311cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void build_def_index(shader_module *);
18411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
18511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// A forward iterator over spirv instructions. Provides easy access to len, opcode, and content words
18611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// without the caller needing to care too much about the physical SPIRV module layout.
18711cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstruct spirv_inst_iter {
18811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::vector<uint32_t>::const_iterator zero;
18911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::vector<uint32_t>::const_iterator it;
19011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
19111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    uint32_t len() {
19211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto result = *it >> 16;
19311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        assert(result > 0);
19411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return result;
19511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
19611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
19711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    uint32_t opcode() { return *it & 0x0ffffu; }
19811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
19911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    uint32_t const &word(unsigned n) {
20011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        assert(n < len());
20111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return it[n];
20211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
20311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
20411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    uint32_t offset() { return (uint32_t)(it - zero); }
20511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
20611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    spirv_inst_iter() {}
20711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
20811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    spirv_inst_iter(std::vector<uint32_t>::const_iterator zero, std::vector<uint32_t>::const_iterator it) : zero(zero), it(it) {}
20911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
21011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool operator==(spirv_inst_iter const &other) { return it == other.it; }
21111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
21211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool operator!=(spirv_inst_iter const &other) { return it != other.it; }
21311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
21411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    spirv_inst_iter operator++(int) { /* x++ */
21511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        spirv_inst_iter ii = *this;
21611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        it += len();
21711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return ii;
21811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
21911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
22011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    spirv_inst_iter operator++() { /* ++x; */
22111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        it += len();
22211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return *this;
22311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
22411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
22511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    /* The iterator and the value are the same thing. */
22611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    spirv_inst_iter &operator*() { return *this; }
22711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    spirv_inst_iter const &operator*() const { return *this; }
22811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert};
22911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
23011cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstruct shader_module {
23111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    /* the spirv image itself */
23211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    vector<uint32_t> words;
23311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    /* a mapping of <id> to the first word of its def. this is useful because walking type
23411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert     * trees, constant expressions, etc requires jumping all over the instruction stream.
23511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert     */
23611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    unordered_map<unsigned, unsigned> def_index;
23711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
23811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    shader_module(VkShaderModuleCreateInfo const *pCreateInfo)
23911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        : words((uint32_t *)pCreateInfo->pCode, (uint32_t *)pCreateInfo->pCode + pCreateInfo->codeSize / sizeof(uint32_t)),
24011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert          def_index() {
24111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
24211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        build_def_index(this);
24311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
24411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
24511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    /* expose begin() / end() to enable range-based for */
24611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    spirv_inst_iter begin() const { return spirv_inst_iter(words.begin(), words.begin() + 5); } /* first insn */
24711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    spirv_inst_iter end() const { return spirv_inst_iter(words.begin(), words.end()); }         /* just past last insn */
24811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    /* given an offset into the module, produce an iterator there. */
24911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    spirv_inst_iter at(unsigned offset) const { return spirv_inst_iter(words.begin(), words.begin() + offset); }
25011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
25111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    /* gets an iterator to the definition of an id */
25211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    spirv_inst_iter get_def(unsigned id) const {
25311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto it = def_index.find(id);
25411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (it == def_index.end()) {
25511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return end();
25611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
25711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return at(it->second);
25811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
25911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert};
26011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
26111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// TODO : This can be much smarter, using separate locks for separate global data
26211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic std::mutex global_lock;
26311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
26411cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic VkDeviceMemory *get_object_mem_binding(layer_data *my_data, uint64_t handle, VkDebugReportObjectTypeEXT type) {
26511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    switch (type) {
26611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT: {
26711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto it = my_data->imageMap.find(VkImage(handle));
26811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (it != my_data->imageMap.end())
26911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return &(*it).second.mem;
27011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        break;
27111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
27211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT: {
27311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto it = my_data->bufferMap.find(VkBuffer(handle));
27411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (it != my_data->bufferMap.end())
27511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return &(*it).second.mem;
27611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        break;
27711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
27811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    default:
27911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        break;
28011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
28111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return nullptr;
28211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
28311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
28411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// prototype
28511cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic GLOBAL_CB_NODE *getCBNode(layer_data const *, const VkCommandBuffer);
28611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
28711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Helper function to validate correct usage bits set for buffers or images
28811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//  Verify that (actual & desired) flags != 0 or,
28911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//   if strict is true, verify that (actual & desired) flags == desired
29011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//  In case of error, report it via dbg callbacks
29111cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validate_usage_flags(layer_data *my_data, VkFlags actual, VkFlags desired, VkBool32 strict,
29211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                     uint64_t obj_handle, VkDebugReportObjectTypeEXT obj_type, char const *ty_str,
29311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                     char const *func_name, char const *usage_str) {
29411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool correct_usage = false;
29511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
29611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (strict)
29711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        correct_usage = ((actual & desired) == desired);
29811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    else
29911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        correct_usage = ((actual & desired) != 0);
30011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!correct_usage) {
30111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, obj_type, obj_handle, __LINE__,
30211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                           MEMTRACK_INVALID_USAGE_FLAG, "MEM", "Invalid usage flag for %s 0x%" PRIxLEAST64
30311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                               " used by %s. In this case, %s should have %s set during creation.",
30411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                           ty_str, obj_handle, func_name, ty_str, usage_str);
30511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
30611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skipCall;
30711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
30811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
30911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Helper function to validate usage flags for images
31011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Pulls image info and then sends actual vs. desired usage off to helper above where
31111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//  an error will be flagged if usage is not correct
31211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validate_image_usage_flags(layer_data *dev_data, VkImage image, VkFlags desired, VkBool32 strict,
31311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                           char const *func_name, char const *usage_string) {
31411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
31511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto const image_node = dev_data->imageMap.find(image);
31611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (image_node != dev_data->imageMap.end()) {
31711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall = validate_usage_flags(dev_data, image_node->second.createInfo.usage, desired, strict, (uint64_t)image,
31811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, "image", func_name, usage_string);
31911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
32011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skipCall;
32111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
32211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
32311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Helper function to validate usage flags for buffers
32411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Pulls buffer info and then sends actual vs. desired usage off to helper above where
32511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//  an error will be flagged if usage is not correct
32611cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validate_buffer_usage_flags(layer_data *dev_data, VkBuffer buffer, VkFlags desired, VkBool32 strict,
32711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            char const *func_name, char const *usage_string) {
32811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
32911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto const buffer_node = dev_data->bufferMap.find(buffer);
33011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (buffer_node != dev_data->bufferMap.end()) {
33111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall = validate_usage_flags(dev_data, buffer_node->second.createInfo.usage, desired, strict, (uint64_t)buffer,
33211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, "buffer", func_name, usage_string);
33311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
33411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skipCall;
33511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
33611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
33711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Return ptr to info in map container containing mem, or NULL if not found
33811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//  Calls to this function should be wrapped in mutex
33911cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic DEVICE_MEM_INFO *get_mem_obj_info(layer_data *dev_data, const VkDeviceMemory mem) {
34011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto item = dev_data->memObjMap.find(mem);
34111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (item != dev_data->memObjMap.end()) {
34211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return &(*item).second;
34311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else {
34411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return NULL;
34511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
34611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
34711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
34811cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void add_mem_obj_info(layer_data *my_data, void *object, const VkDeviceMemory mem,
34911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             const VkMemoryAllocateInfo *pAllocateInfo) {
35011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    assert(object != NULL);
35111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
35211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    memcpy(&my_data->memObjMap[mem].allocInfo, pAllocateInfo, sizeof(VkMemoryAllocateInfo));
35311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODO:  Update for real hardware, actually process allocation info structures
35411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    my_data->memObjMap[mem].allocInfo.pNext = NULL;
35511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    my_data->memObjMap[mem].object = object;
35611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    my_data->memObjMap[mem].mem = mem;
35711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    my_data->memObjMap[mem].image = VK_NULL_HANDLE;
35811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    my_data->memObjMap[mem].memRange.offset = 0;
35911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    my_data->memObjMap[mem].memRange.size = 0;
36011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    my_data->memObjMap[mem].pData = 0;
36111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    my_data->memObjMap[mem].pDriverData = 0;
36211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    my_data->memObjMap[mem].valid = false;
36311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
36411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
36511cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validate_memory_is_valid(layer_data *dev_data, VkDeviceMemory mem, const char *functionName,
36611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                     VkImage image = VK_NULL_HANDLE) {
36711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (mem == MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
36811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto const image_node = dev_data->imageMap.find(image);
36911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (image_node != dev_data->imageMap.end() && !image_node->second.valid) {
37011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
37111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                           (uint64_t)(mem), __LINE__, MEMTRACK_INVALID_USAGE_FLAG, "MEM",
37211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                           "%s: Cannot read invalid swapchain image 0x%" PRIx64 ", please fill the memory before using.",
37311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                           functionName, (uint64_t)(image));
37411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
37511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else {
37611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        DEVICE_MEM_INFO *pMemObj = get_mem_obj_info(dev_data, mem);
37711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (pMemObj && !pMemObj->valid) {
37811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
37911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                           (uint64_t)(mem), __LINE__, MEMTRACK_INVALID_USAGE_FLAG, "MEM",
38011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                           "%s: Cannot read invalid memory 0x%" PRIx64 ", please fill the memory before using.", functionName,
38111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                           (uint64_t)(mem));
38211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
38311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
38411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return false;
38511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
38611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
38711cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void set_memory_valid(layer_data *dev_data, VkDeviceMemory mem, bool valid, VkImage image = VK_NULL_HANDLE) {
38811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (mem == MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
38911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto image_node = dev_data->imageMap.find(image);
39011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (image_node != dev_data->imageMap.end()) {
39111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            image_node->second.valid = valid;
39211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
39311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else {
39411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        DEVICE_MEM_INFO *pMemObj = get_mem_obj_info(dev_data, mem);
39511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (pMemObj) {
39611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pMemObj->valid = valid;
39711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
39811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
39911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
40011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
40111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Find CB Info and add mem reference to list container
40211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Find Mem Obj Info and add CB reference to list container
40311cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool update_cmd_buf_and_mem_references(layer_data *dev_data, const VkCommandBuffer cb, const VkDeviceMemory mem,
40411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                              const char *apiName) {
40511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
40611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
40711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Skip validation if this image was created through WSI
40811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (mem != MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
40911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
41011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // First update CB binding in MemObj mini CB list
41111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        DEVICE_MEM_INFO *pMemInfo = get_mem_obj_info(dev_data, mem);
41211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (pMemInfo) {
41311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pMemInfo->commandBufferBindings.insert(cb);
41411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // Now update CBInfo's Mem reference list
41511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            GLOBAL_CB_NODE *pCBNode = getCBNode(dev_data, cb);
41611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // TODO: keep track of all destroyed CBs so we know if this is a stale or simply invalid object
41711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (pCBNode) {
41811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pCBNode->memObjs.insert(mem);
41911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
42011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
42111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
42211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skipCall;
42311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
42411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// For every mem obj bound to particular CB, free bindings related to that CB
42511cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void clear_cmd_buf_and_mem_references(layer_data *dev_data, GLOBAL_CB_NODE *pCBNode) {
42611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCBNode) {
42711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (pCBNode->memObjs.size() > 0) {
42811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (auto mem : pCBNode->memObjs) {
42911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                DEVICE_MEM_INFO *pInfo = get_mem_obj_info(dev_data, mem);
43011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (pInfo) {
43111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    pInfo->commandBufferBindings.erase(pCBNode->commandBuffer);
43211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
43311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
43411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pCBNode->memObjs.clear();
43511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
43611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCBNode->validate_functions.clear();
43711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
43811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
43911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Overloaded call to above function when GLOBAL_CB_NODE has not already been looked-up
44011cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void clear_cmd_buf_and_mem_references(layer_data *dev_data, const VkCommandBuffer cb) {
44111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    clear_cmd_buf_and_mem_references(dev_data, getCBNode(dev_data, cb));
44211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
44311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
44411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// For given MemObjInfo, report Obj & CB bindings
44511cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool reportMemReferencesAndCleanUp(layer_data *dev_data, DEVICE_MEM_INFO *pMemObjInfo) {
44611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
44711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    size_t cmdBufRefCount = pMemObjInfo->commandBufferBindings.size();
44811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    size_t objRefCount = pMemObjInfo->objBindings.size();
44911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
45011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if ((pMemObjInfo->commandBufferBindings.size()) != 0) {
45111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
45211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                           (uint64_t)pMemObjInfo->mem, __LINE__, MEMTRACK_FREED_MEM_REF, "MEM",
45311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                           "Attempting to free memory object 0x%" PRIxLEAST64 " which still contains " PRINTF_SIZE_T_SPECIFIER
45411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                           " references",
45511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                           (uint64_t)pMemObjInfo->mem, (cmdBufRefCount + objRefCount));
45611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
45711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
45811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (cmdBufRefCount > 0 && pMemObjInfo->commandBufferBindings.size() > 0) {
45911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (auto cb : pMemObjInfo->commandBufferBindings) {
46011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
46111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    (uint64_t)cb, __LINE__, MEMTRACK_FREED_MEM_REF, "MEM",
46211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    "Command Buffer 0x%p still has a reference to mem obj 0x%" PRIxLEAST64, cb, (uint64_t)pMemObjInfo->mem);
46311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
46411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Clear the list of hanging references
46511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pMemObjInfo->commandBufferBindings.clear();
46611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
46711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
46811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (objRefCount > 0 && pMemObjInfo->objBindings.size() > 0) {
46911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (auto obj : pMemObjInfo->objBindings) {
47011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, obj.type, obj.handle, __LINE__,
47111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    MEMTRACK_FREED_MEM_REF, "MEM", "VK Object 0x%" PRIxLEAST64 " still has a reference to mem obj 0x%" PRIxLEAST64,
47211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    obj.handle, (uint64_t)pMemObjInfo->mem);
47311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
47411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Clear the list of hanging references
47511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pMemObjInfo->objBindings.clear();
47611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
47711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skipCall;
47811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
47911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
48011cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool deleteMemObjInfo(layer_data *my_data, void *object, VkDeviceMemory mem) {
48111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
48211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto item = my_data->memObjMap.find(mem);
48311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (item != my_data->memObjMap.end()) {
48411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        my_data->memObjMap.erase(item);
48511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else {
48611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
48711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                           (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MEM_OBJ, "MEM",
48811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                           "Request to delete memory object 0x%" PRIxLEAST64 " not present in memory Object Map", (uint64_t)mem);
48911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
49011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skipCall;
49111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
49211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
49311cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool freeMemObjInfo(layer_data *dev_data, void *object, VkDeviceMemory mem, bool internal) {
49411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
49511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Parse global list to find info w/ mem
49611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    DEVICE_MEM_INFO *pInfo = get_mem_obj_info(dev_data, mem);
49711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pInfo) {
49811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (pInfo->allocInfo.allocationSize == 0 && !internal) {
49911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // TODO: Verify against Valid Use section
50011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
50111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                               (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MEM_OBJ, "MEM",
50211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                               "Attempting to free memory associated with a Persistent Image, 0x%" PRIxLEAST64 ", "
50311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                               "this should not be explicitly freed\n",
50411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                               (uint64_t)mem);
50511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
50611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // Clear any CB bindings for completed CBs
50711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            //   TODO : Is there a better place to do this?
50811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
50911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            assert(pInfo->object != VK_NULL_HANDLE);
51011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // clear_cmd_buf_and_mem_references removes elements from
51111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // pInfo->commandBufferBindings -- this copy not needed in c++14,
51211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // and probably not needed in practice in c++11
51311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            auto bindings = pInfo->commandBufferBindings;
51411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (auto cb : bindings) {
51511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (!dev_data->globalInFlightCmdBuffers.count(cb)) {
51611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    clear_cmd_buf_and_mem_references(dev_data, cb);
51711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
51811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
51911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
52011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // Now verify that no references to this mem obj remain and remove bindings
52111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (pInfo->commandBufferBindings.size() || pInfo->objBindings.size()) {
52211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skipCall |= reportMemReferencesAndCleanUp(dev_data, pInfo);
52311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
52411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // Delete mem obj info
52511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= deleteMemObjInfo(dev_data, object, mem);
52611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
52711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
52811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skipCall;
52911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
53011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
53111cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic const char *object_type_to_string(VkDebugReportObjectTypeEXT type) {
53211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    switch (type) {
53311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT:
53411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "image";
53511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT:
53611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "buffer";
53711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT:
53811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "swapchain";
53911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    default:
54011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "unknown";
54111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
54211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
54311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
54411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Remove object binding performs 3 tasks:
54511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// 1. Remove ObjectInfo from MemObjInfo list container of obj bindings & free it
54611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// 2. Clear mem binding for image/buffer by setting its handle to 0
54711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// TODO : This only applied to Buffer, Image, and Swapchain objects now, how should it be updated/customized?
54811cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool clear_object_binding(layer_data *dev_data, uint64_t handle, VkDebugReportObjectTypeEXT type) {
54911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODO : Need to customize images/buffers/swapchains to track mem binding and clear it here appropriately
55011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
55111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkDeviceMemory *pMemBinding = get_object_mem_binding(dev_data, handle, type);
55211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pMemBinding) {
55311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        DEVICE_MEM_INFO *pMemObjInfo = get_mem_obj_info(dev_data, *pMemBinding);
55411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // TODO : Make sure this is a reasonable way to reset mem binding
55511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        *pMemBinding = VK_NULL_HANDLE;
55611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (pMemObjInfo) {
55711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // This obj is bound to a memory object. Remove the reference to this object in that memory object's list,
55811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // and set the objects memory binding pointer to NULL.
55911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (!pMemObjInfo->objBindings.erase({handle, type})) {
56011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skipCall |=
56111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, type, handle, __LINE__, MEMTRACK_INVALID_OBJECT,
56211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "MEM", "While trying to clear mem binding for %s obj 0x%" PRIxLEAST64
56311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                   ", unable to find that object referenced by mem obj 0x%" PRIxLEAST64,
56411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            object_type_to_string(type), handle, (uint64_t)pMemObjInfo->mem);
56511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
56611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
56711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
56811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skipCall;
56911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
57011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
57111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// For NULL mem case, output warning
57211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Make sure given object is in global object map
57311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//  IF a previous binding existed, output validation error
57411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//  Otherwise, add reference from objectInfo to memoryInfo
57511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//  Add reference off of objInfo
57611cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool set_mem_binding(layer_data *dev_data, VkDeviceMemory mem, uint64_t handle,
57711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                VkDebugReportObjectTypeEXT type, const char *apiName) {
57811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
57911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Handle NULL case separately, just clear previous binding & decrement reference
58011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (mem == VK_NULL_HANDLE) {
58111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // TODO: Verify against Valid Use section of spec.
58211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, type, handle, __LINE__, MEMTRACK_INVALID_MEM_OBJ,
58311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                           "MEM", "In %s, attempting to Bind Obj(0x%" PRIxLEAST64 ") to NULL", apiName, handle);
58411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else {
58511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        VkDeviceMemory *pMemBinding = get_object_mem_binding(dev_data, handle, type);
58611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        assert(pMemBinding);
58711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        DEVICE_MEM_INFO *pMemInfo = get_mem_obj_info(dev_data, mem);
58811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (pMemInfo) {
58911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            DEVICE_MEM_INFO *pPrevBinding = get_mem_obj_info(dev_data, *pMemBinding);
59011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (pPrevBinding != NULL) {
59111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
59211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)mem, __LINE__, MEMTRACK_REBIND_OBJECT,
59311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    "MEM", "In %s, attempting to bind memory (0x%" PRIxLEAST64 ") to object (0x%" PRIxLEAST64
59411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                           ") which has already been bound to mem object 0x%" PRIxLEAST64,
59511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    apiName, (uint64_t)mem, handle, (uint64_t)pPrevBinding->mem);
59611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            } else {
59711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pMemInfo->objBindings.insert({handle, type});
59811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                // For image objects, make sure default memory state is correctly set
59911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                // TODO : What's the best/correct way to handle this?
60011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT == type) {
60111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    auto const image_node = dev_data->imageMap.find(VkImage(handle));
60211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    if (image_node != dev_data->imageMap.end()) {
60311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        VkImageCreateInfo ici = image_node->second.createInfo;
60411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        if (ici.usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
60511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            // TODO::  More memory state transition stuff.
60611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        }
60711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    }
60811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
60911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                *pMemBinding = mem;
61011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
61111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
61211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
61311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skipCall;
61411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
61511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
61611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// For NULL mem case, clear any previous binding Else...
61711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Make sure given object is in its object map
61811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//  IF a previous binding existed, update binding
61911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//  Add reference from objectInfo to memoryInfo
62011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//  Add reference off of object's binding info
62111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Return VK_TRUE if addition is successful, VK_FALSE otherwise
62211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool set_sparse_mem_binding(layer_data *dev_data, VkDeviceMemory mem, uint64_t handle,
62311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                       VkDebugReportObjectTypeEXT type, const char *apiName) {
62411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = VK_FALSE;
62511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Handle NULL case separately, just clear previous binding & decrement reference
62611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (mem == VK_NULL_HANDLE) {
62711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall = clear_object_binding(dev_data, handle, type);
62811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else {
62911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        VkDeviceMemory *pMemBinding = get_object_mem_binding(dev_data, handle, type);
63011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        assert(pMemBinding);
63111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        DEVICE_MEM_INFO *pInfo = get_mem_obj_info(dev_data, mem);
63211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (pInfo) {
63311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pInfo->objBindings.insert({handle, type});
63411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // Need to set mem binding for this object
63511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            *pMemBinding = mem;
63611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
63711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
63811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skipCall;
63911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
64011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
64111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// For given Object, get 'mem' obj that it's bound to or NULL if no binding
64211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool get_mem_binding_from_object(layer_data *dev_data, const uint64_t handle,
64311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            const VkDebugReportObjectTypeEXT type, VkDeviceMemory *mem) {
64411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
64511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    *mem = VK_NULL_HANDLE;
64611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkDeviceMemory *pMemBinding = get_object_mem_binding(dev_data, handle, type);
64711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pMemBinding) {
64811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        *mem = *pMemBinding;
64911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else {
65011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, type, handle, __LINE__, MEMTRACK_INVALID_OBJECT,
65111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                           "MEM", "Trying to get mem binding for object 0x%" PRIxLEAST64 " but no such object in %s list", handle,
65211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                           object_type_to_string(type));
65311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
65411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skipCall;
65511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
65611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
65711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Print details of MemObjInfo list
65811cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void print_mem_list(layer_data *dev_data) {
65911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    DEVICE_MEM_INFO *pInfo = NULL;
66011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
66111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Early out if info is not requested
66211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!(dev_data->report_data->active_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT)) {
66311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return;
66411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
66511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
66611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Just printing each msg individually for now, may want to package these into single large print
66711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, __LINE__,
66811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            MEMTRACK_NONE, "MEM", "Details of Memory Object list (of size " PRINTF_SIZE_T_SPECIFIER " elements)",
66911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            dev_data->memObjMap.size());
67011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, __LINE__,
67111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            MEMTRACK_NONE, "MEM", "=============================");
67211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
67311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (dev_data->memObjMap.size() <= 0)
67411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return;
67511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
67611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto ii = dev_data->memObjMap.begin(); ii != dev_data->memObjMap.end(); ++ii) {
67711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pInfo = &(*ii).second;
67811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
67911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0,
68011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                __LINE__, MEMTRACK_NONE, "MEM", "    ===MemObjInfo at 0x%p===", (void *)pInfo);
68111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0,
68211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                __LINE__, MEMTRACK_NONE, "MEM", "    Mem object: 0x%" PRIxLEAST64, (uint64_t)(pInfo->mem));
68311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0,
68411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                __LINE__, MEMTRACK_NONE, "MEM", "    Ref Count: " PRINTF_SIZE_T_SPECIFIER,
68511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pInfo->commandBufferBindings.size() + pInfo->objBindings.size());
68611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (0 != pInfo->allocInfo.allocationSize) {
68711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            string pAllocInfoMsg = vk_print_vkmemoryallocateinfo(&pInfo->allocInfo, "MEM(INFO):         ");
68811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0,
68911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    __LINE__, MEMTRACK_NONE, "MEM", "    Mem Alloc info:\n%s", pAllocInfoMsg.c_str());
69011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
69111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0,
69211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    __LINE__, MEMTRACK_NONE, "MEM", "    Mem Alloc info is NULL (alloc done by vkCreateSwapchainKHR())");
69311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
69411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
69511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0,
69611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                __LINE__, MEMTRACK_NONE, "MEM", "    VK OBJECT Binding list of size " PRINTF_SIZE_T_SPECIFIER " elements:",
69711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pInfo->objBindings.size());
69811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (pInfo->objBindings.size() > 0) {
69911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (auto obj : pInfo->objBindings) {
70011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
70111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        0, __LINE__, MEMTRACK_NONE, "MEM", "       VK OBJECT 0x%" PRIx64, obj.handle);
70211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
70311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
70411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
70511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0,
70611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                __LINE__, MEMTRACK_NONE, "MEM",
70711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                "    VK Command Buffer (CB) binding list of size " PRINTF_SIZE_T_SPECIFIER " elements",
70811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pInfo->commandBufferBindings.size());
70911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (pInfo->commandBufferBindings.size() > 0) {
71011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (auto cb : pInfo->commandBufferBindings) {
71111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
71211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        0, __LINE__, MEMTRACK_NONE, "MEM", "      VK CB 0x%p", cb);
71311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
71411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
71511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
71611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
71711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
71811cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void printCBList(layer_data *my_data) {
71911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCBInfo = NULL;
72011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
72111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Early out if info is not requested
72211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!(my_data->report_data->active_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT)) {
72311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return;
72411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
72511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
72611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, __LINE__,
72711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            MEMTRACK_NONE, "MEM", "Details of CB list (of size " PRINTF_SIZE_T_SPECIFIER " elements)",
72811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            my_data->commandBufferMap.size());
72911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, __LINE__,
73011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            MEMTRACK_NONE, "MEM", "==================");
73111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
73211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (my_data->commandBufferMap.size() <= 0)
73311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return;
73411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
73511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto &cb_node : my_data->commandBufferMap) {
73611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCBInfo = cb_node.second;
73711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
73811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0,
73911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                __LINE__, MEMTRACK_NONE, "MEM", "    CB Info (0x%p) has CB 0x%p", (void *)pCBInfo, (void *)pCBInfo->commandBuffer);
74011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
74111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (pCBInfo->memObjs.size() <= 0)
74211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            continue;
74311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (auto obj : pCBInfo->memObjs) {
74411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0,
74511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    __LINE__, MEMTRACK_NONE, "MEM", "      Mem obj 0x%" PRIx64, (uint64_t)obj);
74611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
74711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
74811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
74911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
75011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Return a string representation of CMD_TYPE enum
75111cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic string cmdTypeToString(CMD_TYPE cmd) {
75211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    switch (cmd) {
75311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_BINDPIPELINE:
75411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_BINDPIPELINE";
75511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_BINDPIPELINEDELTA:
75611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_BINDPIPELINEDELTA";
75711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_SETVIEWPORTSTATE:
75811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_SETVIEWPORTSTATE";
75911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_SETLINEWIDTHSTATE:
76011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_SETLINEWIDTHSTATE";
76111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_SETDEPTHBIASSTATE:
76211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_SETDEPTHBIASSTATE";
76311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_SETBLENDSTATE:
76411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_SETBLENDSTATE";
76511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_SETDEPTHBOUNDSSTATE:
76611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_SETDEPTHBOUNDSSTATE";
76711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_SETSTENCILREADMASKSTATE:
76811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_SETSTENCILREADMASKSTATE";
76911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_SETSTENCILWRITEMASKSTATE:
77011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_SETSTENCILWRITEMASKSTATE";
77111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_SETSTENCILREFERENCESTATE:
77211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_SETSTENCILREFERENCESTATE";
77311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_BINDDESCRIPTORSETS:
77411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_BINDDESCRIPTORSETS";
77511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_BINDINDEXBUFFER:
77611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_BINDINDEXBUFFER";
77711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_BINDVERTEXBUFFER:
77811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_BINDVERTEXBUFFER";
77911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_DRAW:
78011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_DRAW";
78111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_DRAWINDEXED:
78211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_DRAWINDEXED";
78311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_DRAWINDIRECT:
78411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_DRAWINDIRECT";
78511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_DRAWINDEXEDINDIRECT:
78611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_DRAWINDEXEDINDIRECT";
78711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_DISPATCH:
78811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_DISPATCH";
78911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_DISPATCHINDIRECT:
79011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_DISPATCHINDIRECT";
79111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_COPYBUFFER:
79211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_COPYBUFFER";
79311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_COPYIMAGE:
79411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_COPYIMAGE";
79511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_BLITIMAGE:
79611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_BLITIMAGE";
79711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_COPYBUFFERTOIMAGE:
79811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_COPYBUFFERTOIMAGE";
79911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_COPYIMAGETOBUFFER:
80011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_COPYIMAGETOBUFFER";
80111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_CLONEIMAGEDATA:
80211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_CLONEIMAGEDATA";
80311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_UPDATEBUFFER:
80411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_UPDATEBUFFER";
80511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_FILLBUFFER:
80611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_FILLBUFFER";
80711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_CLEARCOLORIMAGE:
80811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_CLEARCOLORIMAGE";
80911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_CLEARATTACHMENTS:
81011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_CLEARCOLORATTACHMENT";
81111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_CLEARDEPTHSTENCILIMAGE:
81211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_CLEARDEPTHSTENCILIMAGE";
81311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_RESOLVEIMAGE:
81411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_RESOLVEIMAGE";
81511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_SETEVENT:
81611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_SETEVENT";
81711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_RESETEVENT:
81811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_RESETEVENT";
81911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_WAITEVENTS:
82011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_WAITEVENTS";
82111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_PIPELINEBARRIER:
82211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_PIPELINEBARRIER";
82311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_BEGINQUERY:
82411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_BEGINQUERY";
82511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_ENDQUERY:
82611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_ENDQUERY";
82711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_RESETQUERYPOOL:
82811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_RESETQUERYPOOL";
82911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_COPYQUERYPOOLRESULTS:
83011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_COPYQUERYPOOLRESULTS";
83111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_WRITETIMESTAMP:
83211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_WRITETIMESTAMP";
83311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_INITATOMICCOUNTERS:
83411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_INITATOMICCOUNTERS";
83511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_LOADATOMICCOUNTERS:
83611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_LOADATOMICCOUNTERS";
83711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_SAVEATOMICCOUNTERS:
83811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_SAVEATOMICCOUNTERS";
83911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_BEGINRENDERPASS:
84011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_BEGINRENDERPASS";
84111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case CMD_ENDRENDERPASS:
84211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "CMD_ENDRENDERPASS";
84311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    default:
84411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "UNKNOWN";
84511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
84611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
84711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
84811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// SPIRV utility functions
84911cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void build_def_index(shader_module *module) {
85011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto insn : *module) {
85111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        switch (insn.opcode()) {
85211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        /* Types */
85311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case spv::OpTypeVoid:
85411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case spv::OpTypeBool:
85511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case spv::OpTypeInt:
85611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case spv::OpTypeFloat:
85711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case spv::OpTypeVector:
85811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case spv::OpTypeMatrix:
85911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case spv::OpTypeImage:
86011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case spv::OpTypeSampler:
86111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case spv::OpTypeSampledImage:
86211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case spv::OpTypeArray:
86311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case spv::OpTypeRuntimeArray:
86411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case spv::OpTypeStruct:
86511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case spv::OpTypeOpaque:
86611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case spv::OpTypePointer:
86711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case spv::OpTypeFunction:
86811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case spv::OpTypeEvent:
86911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case spv::OpTypeDeviceEvent:
87011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case spv::OpTypeReserveId:
87111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case spv::OpTypeQueue:
87211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case spv::OpTypePipe:
87311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            module->def_index[insn.word(1)] = insn.offset();
87411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            break;
87511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
87611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        /* Fixed constants */
87711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case spv::OpConstantTrue:
87811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case spv::OpConstantFalse:
87911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case spv::OpConstant:
88011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case spv::OpConstantComposite:
88111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case spv::OpConstantSampler:
88211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case spv::OpConstantNull:
88311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            module->def_index[insn.word(2)] = insn.offset();
88411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            break;
88511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
88611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        /* Specialization constants */
88711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case spv::OpSpecConstantTrue:
88811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case spv::OpSpecConstantFalse:
88911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case spv::OpSpecConstant:
89011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case spv::OpSpecConstantComposite:
89111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case spv::OpSpecConstantOp:
89211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            module->def_index[insn.word(2)] = insn.offset();
89311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            break;
89411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
89511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        /* Variables */
89611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case spv::OpVariable:
89711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            module->def_index[insn.word(2)] = insn.offset();
89811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            break;
89911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
90011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        /* Functions */
90111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case spv::OpFunction:
90211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            module->def_index[insn.word(2)] = insn.offset();
90311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            break;
90411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
90511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        default:
90611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            /* We don't care about any other defs for now. */
90711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            break;
90811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
90911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
91011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
91111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
91211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic spirv_inst_iter find_entrypoint(shader_module *src, char const *name, VkShaderStageFlagBits stageBits) {
91311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto insn : *src) {
91411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (insn.opcode() == spv::OpEntryPoint) {
91511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            auto entrypointName = (char const *)&insn.word(3);
91611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            auto entrypointStageBits = 1u << insn.word(1);
91711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
91811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (!strcmp(entrypointName, name) && (entrypointStageBits & stageBits)) {
91911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                return insn;
92011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
92111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
92211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
92311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
92411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return src->end();
92511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
92611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
92711cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic char const *storage_class_name(unsigned sc) {
92811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    switch (sc) {
92911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::StorageClassInput:
93011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "input";
93111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::StorageClassOutput:
93211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "output";
93311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::StorageClassUniformConstant:
93411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "const uniform";
93511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::StorageClassUniform:
93611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "uniform";
93711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::StorageClassWorkgroup:
93811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "workgroup local";
93911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::StorageClassCrossWorkgroup:
94011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "workgroup global";
94111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::StorageClassPrivate:
94211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "private global";
94311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::StorageClassFunction:
94411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "function";
94511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::StorageClassGeneric:
94611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "generic";
94711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::StorageClassAtomicCounter:
94811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "atomic counter";
94911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::StorageClassImage:
95011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "image";
95111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::StorageClassPushConstant:
95211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "push constant";
95311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    default:
95411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return "unknown";
95511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
95611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
95711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
95811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert/* get the value of an integral constant */
95911cd02dfb91661c65134cac258cf5924270e9d2Dan Albertunsigned get_constant_value(shader_module const *src, unsigned id) {
96011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto value = src->get_def(id);
96111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    assert(value != src->end());
96211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
96311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (value.opcode() != spv::OpConstant) {
96411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        /* TODO: Either ensure that the specialization transform is already performed on a module we're
96511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            considering here, OR -- specialize on the fly now.
96611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            */
96711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return 1;
96811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
96911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
97011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return value.word(3);
97111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
97211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
97311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
97411cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void describe_type_inner(std::ostringstream &ss, shader_module const *src, unsigned type) {
97511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto insn = src->get_def(type);
97611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    assert(insn != src->end());
97711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
97811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    switch (insn.opcode()) {
97911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::OpTypeBool:
98011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        ss << "bool";
98111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        break;
98211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::OpTypeInt:
98311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        ss << (insn.word(3) ? 's' : 'u') << "int" << insn.word(2);
98411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        break;
98511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::OpTypeFloat:
98611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        ss << "float" << insn.word(2);
98711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        break;
98811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::OpTypeVector:
98911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        ss << "vec" << insn.word(3) << " of ";
99011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        describe_type_inner(ss, src, insn.word(2));
99111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        break;
99211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::OpTypeMatrix:
99311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        ss << "mat" << insn.word(3) << " of ";
99411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        describe_type_inner(ss, src, insn.word(2));
99511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        break;
99611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::OpTypeArray:
99711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        ss << "arr[" << get_constant_value(src, insn.word(3)) << "] of ";
99811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        describe_type_inner(ss, src, insn.word(2));
99911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        break;
100011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::OpTypePointer:
100111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        ss << "ptr to " << storage_class_name(insn.word(2)) << " ";
100211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        describe_type_inner(ss, src, insn.word(3));
100311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        break;
100411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::OpTypeStruct: {
100511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        ss << "struct of (";
100611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (unsigned i = 2; i < insn.len(); i++) {
100711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            describe_type_inner(ss, src, insn.word(i));
100811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (i == insn.len() - 1) {
100911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                ss << ")";
101011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            } else {
101111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                ss << ", ";
101211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
101311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
101411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        break;
101511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
101611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::OpTypeSampler:
101711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        ss << "sampler";
101811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        break;
101911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::OpTypeSampledImage:
102011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        ss << "sampler+";
102111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        describe_type_inner(ss, src, insn.word(2));
102211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        break;
102311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::OpTypeImage:
102411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        ss << "image(dim=" << insn.word(3) << ", sampled=" << insn.word(7) << ")";
102511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        break;
102611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    default:
102711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        ss << "oddtype";
102811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        break;
102911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
103011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
103111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
103211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
103311cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic std::string describe_type(shader_module const *src, unsigned type) {
103411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::ostringstream ss;
103511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    describe_type_inner(ss, src, type);
103611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return ss.str();
103711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
103811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
103911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
104011cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool is_narrow_numeric_type(spirv_inst_iter type)
104111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert{
104211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (type.opcode() != spv::OpTypeInt && type.opcode() != spv::OpTypeFloat)
104311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return false;
104411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return type.word(2) < 64;
104511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
104611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
104711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
104811cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool types_match(shader_module const *a, shader_module const *b, unsigned a_type, unsigned b_type, bool a_arrayed, bool b_arrayed, bool relaxed) {
104911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    /* walk two type trees together, and complain about differences */
105011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto a_insn = a->get_def(a_type);
105111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto b_insn = b->get_def(b_type);
105211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    assert(a_insn != a->end());
105311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    assert(b_insn != b->end());
105411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
105511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (a_arrayed && a_insn.opcode() == spv::OpTypeArray) {
105611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return types_match(a, b, a_insn.word(2), b_type, false, b_arrayed, relaxed);
105711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
105811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
105911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (b_arrayed && b_insn.opcode() == spv::OpTypeArray) {
106011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        /* we probably just found the extra level of arrayness in b_type: compare the type inside it to a_type */
106111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return types_match(a, b, a_type, b_insn.word(2), a_arrayed, false, relaxed);
106211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
106311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
106411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (a_insn.opcode() == spv::OpTypeVector && relaxed && is_narrow_numeric_type(b_insn)) {
106511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return types_match(a, b, a_insn.word(2), b_type, a_arrayed, b_arrayed, false);
106611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
106711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
106811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (a_insn.opcode() != b_insn.opcode()) {
106911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return false;
107011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
107111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
107211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (a_insn.opcode() == spv::OpTypePointer) {
107311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        /* match on pointee type. storage class is expected to differ */
107411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return types_match(a, b, a_insn.word(3), b_insn.word(3), a_arrayed, b_arrayed, relaxed);
107511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
107611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
107711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (a_arrayed || b_arrayed) {
107811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        /* if we havent resolved array-of-verts by here, we're not going to. */
107911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return false;
108011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
108111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
108211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    switch (a_insn.opcode()) {
108311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::OpTypeBool:
108411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return true;
108511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::OpTypeInt:
108611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        /* match on width, signedness */
108711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return a_insn.word(2) == b_insn.word(2) && a_insn.word(3) == b_insn.word(3);
108811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::OpTypeFloat:
108911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        /* match on width */
109011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return a_insn.word(2) == b_insn.word(2);
109111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::OpTypeVector:
109211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        /* match on element type, count. */
109311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!types_match(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false))
109411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return false;
109511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (relaxed && is_narrow_numeric_type(a->get_def(a_insn.word(2)))) {
109611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return a_insn.word(3) >= b_insn.word(3);
109711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
109811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        else {
109911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return a_insn.word(3) == b_insn.word(3);
110011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
110111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::OpTypeMatrix:
110211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        /* match on element type, count. */
110311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return types_match(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false) && a_insn.word(3) == b_insn.word(3);
110411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::OpTypeArray:
110511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        /* match on element type, count. these all have the same layout. we don't get here if
110611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert         * b_arrayed. This differs from vector & matrix types in that the array size is the id of a constant instruction,
110711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert         * not a literal within OpTypeArray */
110811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return types_match(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false) &&
110911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert               get_constant_value(a, a_insn.word(3)) == get_constant_value(b, b_insn.word(3));
111011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::OpTypeStruct:
111111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        /* match on all element types */
111211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {
111311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (a_insn.len() != b_insn.len()) {
111411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                return false; /* structs cannot match if member counts differ */
111511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
111611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
111711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (unsigned i = 2; i < a_insn.len(); i++) {
111811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (!types_match(a, b, a_insn.word(i), b_insn.word(i), a_arrayed, b_arrayed, false)) {
111911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    return false;
112011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
112111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
112211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
112311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return true;
112411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
112511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    default:
112611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        /* remaining types are CLisms, or may not appear in the interfaces we
112711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert         * are interested in. Just claim no match.
112811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert         */
112911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return false;
113011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
113111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
113211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
113311cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic int value_or_default(std::unordered_map<unsigned, unsigned> const &map, unsigned id, int def) {
113411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto it = map.find(id);
113511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (it == map.end())
113611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return def;
113711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    else
113811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return it->second;
113911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
114011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
114111cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic unsigned get_locations_consumed_by_type(shader_module const *src, unsigned type, bool strip_array_level) {
114211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto insn = src->get_def(type);
114311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    assert(insn != src->end());
114411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
114511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    switch (insn.opcode()) {
114611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::OpTypePointer:
114711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        /* see through the ptr -- this is only ever at the toplevel for graphics shaders;
114811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert         * we're never actually passing pointers around. */
114911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return get_locations_consumed_by_type(src, insn.word(3), strip_array_level);
115011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::OpTypeArray:
115111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (strip_array_level) {
115211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return get_locations_consumed_by_type(src, insn.word(2), false);
115311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
115411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return get_constant_value(src, insn.word(3)) * get_locations_consumed_by_type(src, insn.word(2), false);
115511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
115611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::OpTypeMatrix:
115711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        /* num locations is the dimension * element size */
115811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return insn.word(3) * get_locations_consumed_by_type(src, insn.word(2), false);
115911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::OpTypeVector: {
116011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto scalar_type = src->get_def(insn.word(2));
116111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto bit_width = (scalar_type.opcode() == spv::OpTypeInt || scalar_type.opcode() == spv::OpTypeFloat) ?
116211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            scalar_type.word(2) : 32;
116311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
116411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        /* locations are 128-bit wide; 3- and 4-component vectors of 64 bit
116511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert         * types require two. */
116611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return (bit_width * insn.word(3) + 127) / 128;
116711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
116811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    default:
116911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        /* everything else is just 1. */
117011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return 1;
117111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
117211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        /* TODO: extend to handle 64bit scalar types, whose vectors may need
117311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert         * multiple locations. */
117411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
117511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
117611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
117711cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic unsigned get_locations_consumed_by_format(VkFormat format) {
117811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    switch (format) {
117911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R64G64B64A64_SFLOAT:
118011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R64G64B64A64_SINT:
118111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R64G64B64A64_UINT:
118211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R64G64B64_SFLOAT:
118311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R64G64B64_SINT:
118411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R64G64B64_UINT:
118511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return 2;
118611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    default:
118711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return 1;
118811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
118911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
119011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
119111cd02dfb91661c65134cac258cf5924270e9d2Dan Alberttypedef std::pair<unsigned, unsigned> location_t;
119211cd02dfb91661c65134cac258cf5924270e9d2Dan Alberttypedef std::pair<unsigned, unsigned> descriptor_slot_t;
119311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
119411cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstruct interface_var {
119511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    uint32_t id;
119611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    uint32_t type_id;
119711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    uint32_t offset;
119811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool is_patch;
119911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool is_block_member;
120011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    /* TODO: collect the name, too? Isn't required to be present. */
120111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert};
120211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
120311cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstruct shader_stage_attributes {
120411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    char const *const name;
120511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool arrayed_input;
120611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool arrayed_output;
120711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert};
120811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
120911cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic shader_stage_attributes shader_stage_attribs[] = {
121011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    {"vertex shader", false, false},
121111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    {"tessellation control shader", true, true},
121211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    {"tessellation evaluation shader", true, false},
121311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    {"geometry shader", true, false},
121411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    {"fragment shader", false, false},
121511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert};
121611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
121711cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic spirv_inst_iter get_struct_type(shader_module const *src, spirv_inst_iter def, bool is_array_of_verts) {
121811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    while (true) {
121911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
122011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (def.opcode() == spv::OpTypePointer) {
122111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            def = src->get_def(def.word(3));
122211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else if (def.opcode() == spv::OpTypeArray && is_array_of_verts) {
122311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            def = src->get_def(def.word(2));
122411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            is_array_of_verts = false;
122511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else if (def.opcode() == spv::OpTypeStruct) {
122611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return def;
122711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
122811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return src->end();
122911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
123011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
123111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
123211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
123311cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void collect_interface_block_members(shader_module const *src,
123411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            std::map<location_t, interface_var> &out,
123511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            std::unordered_map<unsigned, unsigned> const &blocks, bool is_array_of_verts,
123611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            uint32_t id, uint32_t type_id, bool is_patch) {
123711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    /* Walk down the type_id presented, trying to determine whether it's actually an interface block. */
123811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto type = get_struct_type(src, src->get_def(type_id), is_array_of_verts && !is_patch);
123911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (type == src->end() || blocks.find(type.word(1)) == blocks.end()) {
124011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        /* this isn't an interface block. */
124111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return;
124211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
124311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
124411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unordered_map<unsigned, unsigned> member_components;
124511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
124611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    /* Walk all the OpMemberDecorate for type's result id -- first pass, collect components. */
124711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto insn : *src) {
124811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
124911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            unsigned member_index = insn.word(2);
125011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
125111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (insn.word(3) == spv::DecorationComponent) {
125211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                unsigned component = insn.word(4);
125311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                member_components[member_index] = component;
125411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
125511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
125611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
125711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
125811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    /* Second pass -- produce the output, from Location decorations */
125911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto insn : *src) {
126011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
126111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            unsigned member_index = insn.word(2);
126211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            unsigned member_type_id = type.word(2 + member_index);
126311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
126411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (insn.word(3) == spv::DecorationLocation) {
126511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                unsigned location = insn.word(4);
126611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                unsigned num_locations = get_locations_consumed_by_type(src, member_type_id, false);
126711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                auto component_it = member_components.find(member_index);
126811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                unsigned component = component_it == member_components.end() ? 0 : component_it->second;
126911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
127011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                for (unsigned int offset = 0; offset < num_locations; offset++) {
127111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    interface_var v;
127211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    v.id = id;
127311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    /* TODO: member index in interface_var too? */
127411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    v.type_id = member_type_id;
127511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    v.offset = offset;
127611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    v.is_patch = is_patch;
127711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    v.is_block_member = true;
127811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    out[std::make_pair(location + offset, component)] = v;
127911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
128011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
128111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
128211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
128311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
128411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
128511cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void collect_interface_by_location(shader_module const *src, spirv_inst_iter entrypoint,
128611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                          spv::StorageClass sinterface, std::map<location_t, interface_var> &out,
128711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                          bool is_array_of_verts) {
128811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unordered_map<unsigned, unsigned> var_locations;
128911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unordered_map<unsigned, unsigned> var_builtins;
129011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unordered_map<unsigned, unsigned> var_components;
129111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unordered_map<unsigned, unsigned> blocks;
129211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unordered_map<unsigned, unsigned> var_patch;
129311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
129411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto insn : *src) {
129511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
129611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        /* We consider two interface models: SSO rendezvous-by-location, and
129711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert         * builtins. Complain about anything that fits neither model.
129811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert         */
129911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (insn.opcode() == spv::OpDecorate) {
130011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (insn.word(2) == spv::DecorationLocation) {
130111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                var_locations[insn.word(1)] = insn.word(3);
130211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
130311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
130411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (insn.word(2) == spv::DecorationBuiltIn) {
130511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                var_builtins[insn.word(1)] = insn.word(3);
130611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
130711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
130811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (insn.word(2) == spv::DecorationComponent) {
130911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                var_components[insn.word(1)] = insn.word(3);
131011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
131111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
131211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (insn.word(2) == spv::DecorationBlock) {
131311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                blocks[insn.word(1)] = 1;
131411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
131511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
131611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (insn.word(2) == spv::DecorationPatch) {
131711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                var_patch[insn.word(1)] = 1;
131811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
131911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
132011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
132111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
132211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    /* TODO: handle grouped decorations */
132311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    /* TODO: handle index=1 dual source outputs from FS -- two vars will
132411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert     * have the same location, and we DON'T want to clobber. */
132511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
132611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    /* find the end of the entrypoint's name string. additional zero bytes follow the actual null
132711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert       terminator, to fill out the rest of the word - so we only need to look at the last byte in
132811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert       the word to determine which word contains the terminator. */
132911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    uint32_t word = 3;
133011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    while (entrypoint.word(word) & 0xff000000u) {
133111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        ++word;
133211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
133311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    ++word;
133411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
133511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (; word < entrypoint.len(); word++) {
133611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto insn = src->get_def(entrypoint.word(word));
133711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        assert(insn != src->end());
133811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        assert(insn.opcode() == spv::OpVariable);
133911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
134011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (insn.word(3) == static_cast<uint32_t>(sinterface)) {
134111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            unsigned id = insn.word(2);
134211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            unsigned type = insn.word(1);
134311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
134411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            int location = value_or_default(var_locations, id, -1);
134511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            int builtin = value_or_default(var_builtins, id, -1);
134611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            unsigned component = value_or_default(var_components, id, 0); /* unspecified is OK, is 0 */
134711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            bool is_patch = var_patch.find(id) != var_patch.end();
134811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
134911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            /* All variables and interface block members in the Input or Output storage classes
135011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert             * must be decorated with either a builtin or an explicit location.
135111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert             *
135211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert             * TODO: integrate the interface block support here. For now, don't complain --
135311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert             * a valid SPIRV module will only hit this path for the interface block case, as the
135411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert             * individual members of the type are decorated, rather than variable declarations.
135511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert             */
135611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
135711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (location != -1) {
135811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                /* A user-defined interface variable, with a location. Where a variable
135911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                 * occupied multiple locations, emit one result for each. */
136011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                unsigned num_locations = get_locations_consumed_by_type(src, type, is_array_of_verts && !is_patch);
136111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                for (unsigned int offset = 0; offset < num_locations; offset++) {
136211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    interface_var v;
136311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    v.id = id;
136411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    v.type_id = type;
136511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    v.offset = offset;
136611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    v.is_patch = is_patch;
136711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    v.is_block_member = false;
136811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    out[std::make_pair(location + offset, component)] = v;
136911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
137011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            } else if (builtin == -1) {
137111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                /* An interface block instance */
137211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                collect_interface_block_members(src, out, blocks, is_array_of_verts, id, type, is_patch);
137311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
137411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
137511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
137611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
137711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
137811cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void collect_interface_by_descriptor_slot(debug_report_data *report_data, shader_module const *src,
137911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                 std::unordered_set<uint32_t> const &accessible_ids,
138011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                 std::map<descriptor_slot_t, interface_var> &out) {
138111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
138211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unordered_map<unsigned, unsigned> var_sets;
138311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unordered_map<unsigned, unsigned> var_bindings;
138411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
138511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto insn : *src) {
138611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        /* All variables in the Uniform or UniformConstant storage classes are required to be decorated with both
138711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert         * DecorationDescriptorSet and DecorationBinding.
138811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert         */
138911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (insn.opcode() == spv::OpDecorate) {
139011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (insn.word(2) == spv::DecorationDescriptorSet) {
139111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                var_sets[insn.word(1)] = insn.word(3);
139211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
139311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
139411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (insn.word(2) == spv::DecorationBinding) {
139511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                var_bindings[insn.word(1)] = insn.word(3);
139611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
139711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
139811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
139911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
140011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto id : accessible_ids) {
140111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto insn = src->get_def(id);
140211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        assert(insn != src->end());
140311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
140411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (insn.opcode() == spv::OpVariable &&
140511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            (insn.word(3) == spv::StorageClassUniform || insn.word(3) == spv::StorageClassUniformConstant)) {
140611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            unsigned set = value_or_default(var_sets, insn.word(2), 0);
140711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            unsigned binding = value_or_default(var_bindings, insn.word(2), 0);
140811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
140911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            auto existing_it = out.find(std::make_pair(set, binding));
141011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (existing_it != out.end()) {
141111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                /* conflict within spv image */
141211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
141311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        __LINE__, SHADER_CHECKER_INCONSISTENT_SPIRV, "SC",
141411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "var %d (type %d) in %s interface in descriptor slot (%u,%u) conflicts with existing definition",
141511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        insn.word(2), insn.word(1), storage_class_name(insn.word(3)), existing_it->first.first,
141611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        existing_it->first.second);
141711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
141811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
141911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            interface_var v;
142011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            v.id = insn.word(2);
142111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            v.type_id = insn.word(1);
142211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            v.offset = 0;
142311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            v.is_patch = false;
142411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            v.is_block_member = false;
142511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            out[std::make_pair(set, binding)] = v;
142611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
142711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
142811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
142911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
143011cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validate_interface_between_stages(debug_report_data *report_data, shader_module const *producer,
143111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                              spirv_inst_iter producer_entrypoint, shader_stage_attributes const *producer_stage,
143211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                              shader_module const *consumer, spirv_inst_iter consumer_entrypoint,
143311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                              shader_stage_attributes const *consumer_stage) {
143411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::map<location_t, interface_var> outputs;
143511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::map<location_t, interface_var> inputs;
143611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
143711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool pass = true;
143811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
143911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    collect_interface_by_location(producer, producer_entrypoint, spv::StorageClassOutput, outputs, producer_stage->arrayed_output);
144011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    collect_interface_by_location(consumer, consumer_entrypoint, spv::StorageClassInput, inputs, consumer_stage->arrayed_input);
144111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
144211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto a_it = outputs.begin();
144311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto b_it = inputs.begin();
144411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
144511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    /* maps sorted by key (location); walk them together to find mismatches */
144611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    while ((outputs.size() > 0 && a_it != outputs.end()) || (inputs.size() && b_it != inputs.end())) {
144711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        bool a_at_end = outputs.size() == 0 || a_it == outputs.end();
144811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        bool b_at_end = inputs.size() == 0 || b_it == inputs.end();
144911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto a_first = a_at_end ? std::make_pair(0u, 0u) : a_it->first;
145011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto b_first = b_at_end ? std::make_pair(0u, 0u) : b_it->first;
145111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
145211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (b_at_end || ((!a_at_end) && (a_first < b_first))) {
145311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
145411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        __LINE__, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",
145511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "%s writes to output location %u.%u which is not consumed by %s", producer_stage->name, a_first.first,
145611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        a_first.second, consumer_stage->name)) {
145711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pass = false;
145811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
145911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            a_it++;
146011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else if (a_at_end || a_first > b_first) {
146111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
146211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        __LINE__, SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC",
146311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "%s consumes input location %u.%u which is not written by %s", consumer_stage->name, b_first.first, b_first.second,
146411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        producer_stage->name)) {
146511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pass = false;
146611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
146711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            b_it++;
146811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
146911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // subtleties of arrayed interfaces:
147011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // - if is_patch, then the member is not arrayed, even though the interface may be.
147111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // - if is_block_member, then the extra array level of an arrayed interface is not
147211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            //   expressed in the member type -- it's expressed in the block type.
147311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (!types_match(producer, consumer, a_it->second.type_id, b_it->second.type_id,
147411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             producer_stage->arrayed_output && !a_it->second.is_patch && !a_it->second.is_block_member,
147511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             consumer_stage->arrayed_input && !b_it->second.is_patch && !b_it->second.is_block_member,
147611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             true)) {
147711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
147811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            __LINE__, SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC", "Type mismatch on location %u.%u: '%s' vs '%s'",
147911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            a_first.first, a_first.second,
148011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            describe_type(producer, a_it->second.type_id).c_str(),
148111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            describe_type(consumer, b_it->second.type_id).c_str())) {
148211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    pass = false;
148311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
148411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
148511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (a_it->second.is_patch != b_it->second.is_patch) {
148611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0,
148711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            __LINE__, SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
148811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "Decoration mismatch on location %u.%u: is per-%s in %s stage but "
148911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "per-%s in %s stage", a_first.first, a_first.second,
149011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            a_it->second.is_patch ? "patch" : "vertex", producer_stage->name,
149111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            b_it->second.is_patch ? "patch" : "vertex", consumer_stage->name)) {
149211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    pass = false;
149311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
149411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
149511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            a_it++;
149611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            b_it++;
149711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
149811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
149911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
150011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return pass;
150111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
150211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
150311cd02dfb91661c65134cac258cf5924270e9d2Dan Albertenum FORMAT_TYPE {
150411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    FORMAT_TYPE_UNDEFINED,
150511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    FORMAT_TYPE_FLOAT, /* UNORM, SNORM, FLOAT, USCALED, SSCALED, SRGB -- anything we consider float in the shader */
150611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    FORMAT_TYPE_SINT,
150711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    FORMAT_TYPE_UINT,
150811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert};
150911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
151011cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic unsigned get_format_type(VkFormat fmt) {
151111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    switch (fmt) {
151211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_UNDEFINED:
151311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return FORMAT_TYPE_UNDEFINED;
151411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R8_SINT:
151511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R8G8_SINT:
151611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R8G8B8_SINT:
151711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R8G8B8A8_SINT:
151811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R16_SINT:
151911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R16G16_SINT:
152011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R16G16B16_SINT:
152111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R16G16B16A16_SINT:
152211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R32_SINT:
152311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R32G32_SINT:
152411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R32G32B32_SINT:
152511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R32G32B32A32_SINT:
152611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R64_SINT:
152711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R64G64_SINT:
152811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R64G64B64_SINT:
152911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R64G64B64A64_SINT:
153011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_B8G8R8_SINT:
153111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_B8G8R8A8_SINT:
153211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_A8B8G8R8_SINT_PACK32:
153311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_A2B10G10R10_SINT_PACK32:
153411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_A2R10G10B10_SINT_PACK32:
153511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return FORMAT_TYPE_SINT;
153611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R8_UINT:
153711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R8G8_UINT:
153811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R8G8B8_UINT:
153911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R8G8B8A8_UINT:
154011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R16_UINT:
154111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R16G16_UINT:
154211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R16G16B16_UINT:
154311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R16G16B16A16_UINT:
154411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R32_UINT:
154511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R32G32_UINT:
154611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R32G32B32_UINT:
154711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R32G32B32A32_UINT:
154811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R64_UINT:
154911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R64G64_UINT:
155011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R64G64B64_UINT:
155111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_R64G64B64A64_UINT:
155211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_B8G8R8_UINT:
155311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_B8G8R8A8_UINT:
155411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_A8B8G8R8_UINT_PACK32:
155511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_A2B10G10R10_UINT_PACK32:
155611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_FORMAT_A2R10G10B10_UINT_PACK32:
155711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return FORMAT_TYPE_UINT;
155811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    default:
155911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return FORMAT_TYPE_FLOAT;
156011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
156111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
156211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
156311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert/* characterizes a SPIR-V type appearing in an interface to a FF stage,
156411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * for comparison to a VkFormat's characterization above. */
156511cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic unsigned get_fundamental_type(shader_module const *src, unsigned type) {
156611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto insn = src->get_def(type);
156711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    assert(insn != src->end());
156811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
156911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    switch (insn.opcode()) {
157011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::OpTypeInt:
157111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return insn.word(3) ? FORMAT_TYPE_SINT : FORMAT_TYPE_UINT;
157211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::OpTypeFloat:
157311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return FORMAT_TYPE_FLOAT;
157411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::OpTypeVector:
157511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return get_fundamental_type(src, insn.word(2));
157611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::OpTypeMatrix:
157711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return get_fundamental_type(src, insn.word(2));
157811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::OpTypeArray:
157911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return get_fundamental_type(src, insn.word(2));
158011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::OpTypePointer:
158111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return get_fundamental_type(src, insn.word(3));
158211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    default:
158311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return FORMAT_TYPE_UNDEFINED;
158411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
158511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
158611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
158711cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic uint32_t get_shader_stage_id(VkShaderStageFlagBits stage) {
158811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    uint32_t bit_pos = u_ffs(stage);
158911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return bit_pos - 1;
159011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
159111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
159211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validate_vi_consistency(debug_report_data *report_data, VkPipelineVertexInputStateCreateInfo const *vi) {
159311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    /* walk the binding descriptions, which describe the step rate and stride of each vertex buffer.
159411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert     * each binding should be specified only once.
159511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert     */
159611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unordered_map<uint32_t, VkVertexInputBindingDescription const *> bindings;
159711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool pass = true;
159811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
159911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (unsigned i = 0; i < vi->vertexBindingDescriptionCount; i++) {
160011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto desc = &vi->pVertexBindingDescriptions[i];
160111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto &binding = bindings[desc->binding];
160211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (binding) {
160311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
160411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        __LINE__, SHADER_CHECKER_INCONSISTENT_VI, "SC",
160511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "Duplicate vertex input binding descriptions for binding %d", desc->binding)) {
160611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pass = false;
160711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
160811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
160911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            binding = desc;
161011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
161111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
161211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
161311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return pass;
161411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
161511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
161611cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validate_vi_against_vs_inputs(debug_report_data *report_data, VkPipelineVertexInputStateCreateInfo const *vi,
161711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                          shader_module const *vs, spirv_inst_iter entrypoint) {
161811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::map<location_t, interface_var> inputs;
161911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool pass = true;
162011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
162111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    collect_interface_by_location(vs, entrypoint, spv::StorageClassInput, inputs, false);
162211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
162311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    /* Build index by location */
162411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::map<uint32_t, VkVertexInputAttributeDescription const *> attribs;
162511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (vi) {
162611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (unsigned i = 0; i < vi->vertexAttributeDescriptionCount; i++) {
162711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            auto num_locations = get_locations_consumed_by_format(vi->pVertexAttributeDescriptions[i].format);
162811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (auto j = 0u; j < num_locations; j++) {
162911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                attribs[vi->pVertexAttributeDescriptions[i].location + j] = &vi->pVertexAttributeDescriptions[i];
163011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
163111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
163211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
163311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
163411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto it_a = attribs.begin();
163511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto it_b = inputs.begin();
163611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
163711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    while ((attribs.size() > 0 && it_a != attribs.end()) || (inputs.size() > 0 && it_b != inputs.end())) {
163811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        bool a_at_end = attribs.size() == 0 || it_a == attribs.end();
163911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        bool b_at_end = inputs.size() == 0 || it_b == inputs.end();
164011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto a_first = a_at_end ? 0 : it_a->first;
164111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto b_first = b_at_end ? 0 : it_b->first.first;
164211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!a_at_end && (b_at_end || a_first < b_first)) {
164311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
164411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        __LINE__, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",
164511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "Vertex attribute at location %d not consumed by VS", a_first)) {
164611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pass = false;
164711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
164811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            it_a++;
164911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else if (!b_at_end && (a_at_end || b_first < a_first)) {
165011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0,
165111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        __LINE__, SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "VS consumes input at location %d but not provided",
165211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        b_first)) {
165311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pass = false;
165411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
165511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            it_b++;
165611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
165711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            unsigned attrib_type = get_format_type(it_a->second->format);
165811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            unsigned input_type = get_fundamental_type(vs, it_b->second.type_id);
165911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
166011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            /* type checking */
166111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (attrib_type != FORMAT_TYPE_UNDEFINED && input_type != FORMAT_TYPE_UNDEFINED && attrib_type != input_type) {
166211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
166311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            __LINE__, SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
166411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "Attribute type of `%s` at location %d does not match VS input type of `%s`",
166511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            string_VkFormat(it_a->second->format), a_first,
166611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            describe_type(vs, it_b->second.type_id).c_str())) {
166711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    pass = false;
166811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
166911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
167011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
167111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            /* OK! */
167211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            it_a++;
167311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            it_b++;
167411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
167511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
167611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
167711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return pass;
167811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
167911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
168011cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validate_fs_outputs_against_render_pass(debug_report_data *report_data, shader_module const *fs,
168111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                    spirv_inst_iter entrypoint, RENDER_PASS_NODE const *rp, uint32_t subpass) {
168211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::map<location_t, interface_var> outputs;
168311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::map<uint32_t, VkFormat> color_attachments;
168411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto i = 0u; i < rp->subpassColorFormats[subpass].size(); i++) {
168511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (rp->subpassColorFormats[subpass][i] != VK_FORMAT_UNDEFINED) {
168611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            color_attachments[i] = rp->subpassColorFormats[subpass][i];
168711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
168811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
168911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
169011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool pass = true;
169111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
169211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    /* TODO: dual source blend index (spv::DecIndex, zero if not provided) */
169311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
169411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    collect_interface_by_location(fs, entrypoint, spv::StorageClassOutput, outputs, false);
169511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
169611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto it_a = outputs.begin();
169711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto it_b = color_attachments.begin();
169811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
169911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    /* Walk attachment list and outputs together */
170011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
170111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    while ((outputs.size() > 0 && it_a != outputs.end()) || (color_attachments.size() > 0 && it_b != color_attachments.end())) {
170211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        bool a_at_end = outputs.size() == 0 || it_a == outputs.end();
170311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        bool b_at_end = color_attachments.size() == 0 || it_b == color_attachments.end();
170411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
170511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!a_at_end && (b_at_end || it_a->first.first < it_b->first)) {
170611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
170711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        __LINE__, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",
170811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "FS writes to output location %d with no matching attachment", it_a->first.first)) {
170911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pass = false;
171011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
171111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            it_a++;
171211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else if (!b_at_end && (a_at_end || it_a->first.first > it_b->first)) {
171311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
171411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        __LINE__, SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "Attachment %d not written by FS", it_b->first)) {
171511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pass = false;
171611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
171711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            it_b++;
171811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
171911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            unsigned output_type = get_fundamental_type(fs, it_a->second.type_id);
172011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            unsigned att_type = get_format_type(it_b->second);
172111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
172211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            /* type checking */
172311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (att_type != FORMAT_TYPE_UNDEFINED && output_type != FORMAT_TYPE_UNDEFINED && att_type != output_type) {
172411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
172511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            __LINE__, SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
172611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "Attachment %d of type `%s` does not match FS output type of `%s`", it_b->first,
172711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            string_VkFormat(it_b->second),
172811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            describe_type(fs, it_a->second.type_id).c_str())) {
172911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    pass = false;
173011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
173111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
173211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
173311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            /* OK! */
173411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            it_a++;
173511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            it_b++;
173611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
173711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
173811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
173911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return pass;
174011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
174111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
174211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert/* For some analyses, we need to know about all ids referenced by the static call tree of a particular
174311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * entrypoint. This is important for identifying the set of shader resources actually used by an entrypoint,
174411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * for example.
174511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Note: we only explore parts of the image which might actually contain ids we care about for the above analyses.
174611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert *  - NOT the shader input/output interfaces.
174711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert *
174811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * TODO: The set of interesting opcodes here was determined by eyeballing the SPIRV spec. It might be worth
174911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * converting parts of this to be generated from the machine-readable spec instead.
175011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert */
175111cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void mark_accessible_ids(shader_module const *src, spirv_inst_iter entrypoint, std::unordered_set<uint32_t> &ids) {
175211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unordered_set<uint32_t> worklist;
175311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    worklist.insert(entrypoint.word(2));
175411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
175511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    while (!worklist.empty()) {
175611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto id_iter = worklist.begin();
175711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto id = *id_iter;
175811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        worklist.erase(id_iter);
175911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
176011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto insn = src->get_def(id);
176111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (insn == src->end()) {
176211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            /* id is something we didn't collect in build_def_index. that's OK -- we'll stumble
176311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert             * across all kinds of things here that we may not care about. */
176411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            continue;
176511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
176611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
176711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        /* try to add to the output set */
176811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!ids.insert(id).second) {
176911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            continue; /* if we already saw this id, we don't want to walk it again. */
177011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
177111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
177211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        switch (insn.opcode()) {
177311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case spv::OpFunction:
177411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            /* scan whole body of the function, enlisting anything interesting */
177511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            while (++insn, insn.opcode() != spv::OpFunctionEnd) {
177611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                switch (insn.opcode()) {
177711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpLoad:
177811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpAtomicLoad:
177911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpAtomicExchange:
178011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpAtomicCompareExchange:
178111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpAtomicCompareExchangeWeak:
178211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpAtomicIIncrement:
178311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpAtomicIDecrement:
178411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpAtomicIAdd:
178511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpAtomicISub:
178611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpAtomicSMin:
178711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpAtomicUMin:
178811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpAtomicSMax:
178911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpAtomicUMax:
179011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpAtomicAnd:
179111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpAtomicOr:
179211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpAtomicXor:
179311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    worklist.insert(insn.word(3)); /* ptr */
179411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    break;
179511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpStore:
179611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpAtomicStore:
179711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    worklist.insert(insn.word(1)); /* ptr */
179811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    break;
179911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpAccessChain:
180011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpInBoundsAccessChain:
180111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    worklist.insert(insn.word(3)); /* base ptr */
180211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    break;
180311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpSampledImage:
180411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpImageSampleImplicitLod:
180511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpImageSampleExplicitLod:
180611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpImageSampleDrefImplicitLod:
180711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpImageSampleDrefExplicitLod:
180811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpImageSampleProjImplicitLod:
180911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpImageSampleProjExplicitLod:
181011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpImageSampleProjDrefImplicitLod:
181111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpImageSampleProjDrefExplicitLod:
181211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpImageFetch:
181311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpImageGather:
181411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpImageDrefGather:
181511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpImageRead:
181611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpImage:
181711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpImageQueryFormat:
181811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpImageQueryOrder:
181911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpImageQuerySizeLod:
182011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpImageQuerySize:
182111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpImageQueryLod:
182211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpImageQueryLevels:
182311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpImageQuerySamples:
182411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpImageSparseSampleImplicitLod:
182511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpImageSparseSampleExplicitLod:
182611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpImageSparseSampleDrefImplicitLod:
182711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpImageSparseSampleDrefExplicitLod:
182811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpImageSparseSampleProjImplicitLod:
182911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpImageSparseSampleProjExplicitLod:
183011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpImageSparseSampleProjDrefImplicitLod:
183111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpImageSparseSampleProjDrefExplicitLod:
183211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpImageSparseFetch:
183311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpImageSparseGather:
183411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpImageSparseDrefGather:
183511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpImageTexelPointer:
183611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    worklist.insert(insn.word(3)); /* image or sampled image */
183711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    break;
183811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpImageWrite:
183911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    worklist.insert(insn.word(1)); /* image -- different operand order to above */
184011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    break;
184111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpFunctionCall:
184211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    for (uint32_t i = 3; i < insn.len(); i++) {
184311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        worklist.insert(insn.word(i)); /* fn itself, and all args */
184411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    }
184511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    break;
184611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
184711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                case spv::OpExtInst:
184811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    for (uint32_t i = 5; i < insn.len(); i++) {
184911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        worklist.insert(insn.word(i)); /* operands to ext inst */
185011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    }
185111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    break;
185211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
185311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
185411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            break;
185511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
185611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
185711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
185811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
185911cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validate_push_constant_block_against_pipeline(debug_report_data *report_data,
186011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                          std::vector<VkPushConstantRange> const *pushConstantRanges,
186111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                          shader_module const *src, spirv_inst_iter type,
186211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                          VkShaderStageFlagBits stage) {
186311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool pass = true;
186411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
186511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    /* strip off ptrs etc */
186611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    type = get_struct_type(src, type, false);
186711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    assert(type != src->end());
186811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
186911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    /* validate directly off the offsets. this isn't quite correct for arrays
187011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert     * and matrices, but is a good first step. TODO: arrays, matrices, weird
187111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert     * sizes */
187211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto insn : *src) {
187311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
187411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
187511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (insn.word(3) == spv::DecorationOffset) {
187611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                unsigned offset = insn.word(4);
187711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                auto size = 4; /* bytes; TODO: calculate this based on the type */
187811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
187911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                bool found_range = false;
188011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                for (auto const &range : *pushConstantRanges) {
188111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    if (range.offset <= offset && range.offset + range.size >= offset + size) {
188211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        found_range = true;
188311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
188411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        if ((range.stageFlags & stage) == 0) {
188511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
188611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        __LINE__, SHADER_CHECKER_PUSH_CONSTANT_NOT_ACCESSIBLE_FROM_STAGE, "SC",
188711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        "Push constant range covering variable starting at "
188811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        "offset %u not accessible from stage %s",
188911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        offset, string_VkShaderStageFlagBits(stage))) {
189011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                pass = false;
189111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            }
189211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        }
189311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
189411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        break;
189511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    }
189611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
189711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
189811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (!found_range) {
189911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
190011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                __LINE__, SHADER_CHECKER_PUSH_CONSTANT_OUT_OF_RANGE, "SC",
190111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                "Push constant range covering variable starting at "
190211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                "offset %u not declared in layout",
190311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                offset)) {
190411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        pass = false;
190511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    }
190611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
190711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
190811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
190911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
191011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
191111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return pass;
191211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
191311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
191411cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validate_push_constant_usage(debug_report_data *report_data,
191511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         std::vector<VkPushConstantRange> const *pushConstantRanges, shader_module const *src,
191611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         std::unordered_set<uint32_t> accessible_ids, VkShaderStageFlagBits stage) {
191711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool pass = true;
191811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
191911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto id : accessible_ids) {
192011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto def_insn = src->get_def(id);
192111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (def_insn.opcode() == spv::OpVariable && def_insn.word(3) == spv::StorageClassPushConstant) {
192211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pass &= validate_push_constant_block_against_pipeline(report_data, pushConstantRanges, src,
192311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                 src->get_def(def_insn.word(1)), stage);
192411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
192511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
192611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
192711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return pass;
192811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
192911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
193011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// For given pipelineLayout verify that the set_layout_node at slot.first
193111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//  has the requested binding at slot.second and return ptr to that binding
193211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic VkDescriptorSetLayoutBinding const * get_descriptor_binding(PIPELINE_LAYOUT_NODE const *pipelineLayout, descriptor_slot_t slot) {
193311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
193411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!pipelineLayout)
193511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return nullptr;
193611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
193711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (slot.first >= pipelineLayout->descriptorSetLayouts.size())
193811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return nullptr;
193911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
194011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return pipelineLayout->setLayouts[slot.first]->GetDescriptorSetLayoutBindingPtrFromBinding(slot.second);
194111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
194211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
194311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Block of code at start here for managing/tracking Pipeline state that this layer cares about
194411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
194511cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic uint64_t g_drawCount[NUM_DRAW_TYPES] = {0, 0, 0, 0};
194611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
194711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// TODO : Should be tracking lastBound per commandBuffer and when draws occur, report based on that cmd buffer lastBound
194811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//   Then need to synchronize the accesses based on cmd buffer so that if I'm reading state on one cmd buffer, updates
194911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//   to that same cmd buffer by separate thread are not changing state from underneath us
195011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Track the last cmd buffer touched by this thread
195111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
195211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool hasDrawCmd(GLOBAL_CB_NODE *pCB) {
195311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < NUM_DRAW_TYPES; i++) {
195411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (pCB->drawCount[i])
195511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return true;
195611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
195711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return false;
195811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
195911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
196011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Check object status for selected flag state
196111cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validate_status(layer_data *my_data, GLOBAL_CB_NODE *pNode, CBStatusFlags status_mask, VkFlags msg_flags,
196211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            DRAW_STATE_ERROR error_code, const char *fail_msg) {
196311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!(pNode->status & status_mask)) {
196411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return log_msg(my_data->report_data, msg_flags, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
196511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                       reinterpret_cast<const uint64_t &>(pNode->commandBuffer), __LINE__, error_code, "DS",
196611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                       "CB object 0x%" PRIxLEAST64 ": %s", reinterpret_cast<const uint64_t &>(pNode->commandBuffer), fail_msg);
196711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
196811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return false;
196911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
197011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
197111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Retrieve pipeline node ptr for given pipeline object
197211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic PIPELINE_NODE *getPipeline(layer_data const *my_data, VkPipeline pipeline) {
197311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto it = my_data->pipelineMap.find(pipeline);
197411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (it == my_data->pipelineMap.end()) {
197511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return nullptr;
197611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
197711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return it->second;
197811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
197911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
198011cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic RENDER_PASS_NODE *getRenderPass(layer_data const *my_data, VkRenderPass renderpass) {
198111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto it = my_data->renderPassMap.find(renderpass);
198211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (it == my_data->renderPassMap.end()) {
198311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return nullptr;
198411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
198511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return it->second;
198611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
198711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
198811cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic FRAMEBUFFER_NODE *getFramebuffer(layer_data *my_data, VkFramebuffer framebuffer) {
198911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto it = my_data->frameBufferMap.find(framebuffer);
199011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (it == my_data->frameBufferMap.end()) {
199111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return nullptr;
199211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
199311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return &it->second;
199411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
199511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
199611cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic cvdescriptorset::DescriptorSetLayout const *getDescriptorSetLayout(layer_data const *my_data, VkDescriptorSetLayout dsLayout) {
199711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto it = my_data->descriptorSetLayoutMap.find(dsLayout);
199811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (it == my_data->descriptorSetLayoutMap.end()) {
199911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return nullptr;
200011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
200111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return it->second;
200211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
200311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
200411cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic PIPELINE_LAYOUT_NODE const *getPipelineLayout(layer_data const *my_data, VkPipelineLayout pipeLayout) {
200511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto it = my_data->pipelineLayoutMap.find(pipeLayout);
200611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (it == my_data->pipelineLayoutMap.end()) {
200711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return nullptr;
200811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
200911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return &it->second;
201011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
201111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
201211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Return true if for a given PSO, the given state enum is dynamic, else return false
201311cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool isDynamic(const PIPELINE_NODE *pPipeline, const VkDynamicState state) {
201411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pPipeline && pPipeline->graphicsPipelineCI.pDynamicState) {
201511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t i = 0; i < pPipeline->graphicsPipelineCI.pDynamicState->dynamicStateCount; i++) {
201611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (state == pPipeline->graphicsPipelineCI.pDynamicState->pDynamicStates[i])
201711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                return true;
201811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
201911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
202011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return false;
202111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
202211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
202311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Validate state stored as flags at time of draw call
202411cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validate_draw_state_flags(layer_data *dev_data, GLOBAL_CB_NODE *pCB, const PIPELINE_NODE *pPipe, bool indexedDraw) {
202511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool result;
202611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    result = validate_status(dev_data, pCB, CBSTATUS_VIEWPORT_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_VIEWPORT_NOT_BOUND,
202711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             "Dynamic viewport state not set for this command buffer");
202811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    result |= validate_status(dev_data, pCB, CBSTATUS_SCISSOR_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_SCISSOR_NOT_BOUND,
202911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                              "Dynamic scissor state not set for this command buffer");
203011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pPipe->graphicsPipelineCI.pInputAssemblyState &&
203111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        ((pPipe->graphicsPipelineCI.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST) ||
203211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert         (pPipe->graphicsPipelineCI.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP))) {
203311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        result |= validate_status(dev_data, pCB, CBSTATUS_LINE_WIDTH_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
203411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                  DRAWSTATE_LINE_WIDTH_NOT_BOUND, "Dynamic line width state not set for this command buffer");
203511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
203611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pPipe->graphicsPipelineCI.pRasterizationState &&
203711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        (pPipe->graphicsPipelineCI.pRasterizationState->depthBiasEnable == VK_TRUE)) {
203811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        result |= validate_status(dev_data, pCB, CBSTATUS_DEPTH_BIAS_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
203911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                  DRAWSTATE_DEPTH_BIAS_NOT_BOUND, "Dynamic depth bias state not set for this command buffer");
204011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
204111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pPipe->blendConstantsEnabled) {
204211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        result |= validate_status(dev_data, pCB, CBSTATUS_BLEND_CONSTANTS_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
204311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                  DRAWSTATE_BLEND_NOT_BOUND, "Dynamic blend constants state not set for this command buffer");
204411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
204511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pPipe->graphicsPipelineCI.pDepthStencilState &&
204611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        (pPipe->graphicsPipelineCI.pDepthStencilState->depthBoundsTestEnable == VK_TRUE)) {
204711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        result |= validate_status(dev_data, pCB, CBSTATUS_DEPTH_BOUNDS_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
204811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                  DRAWSTATE_DEPTH_BOUNDS_NOT_BOUND, "Dynamic depth bounds state not set for this command buffer");
204911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
205011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pPipe->graphicsPipelineCI.pDepthStencilState &&
205111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        (pPipe->graphicsPipelineCI.pDepthStencilState->stencilTestEnable == VK_TRUE)) {
205211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        result |= validate_status(dev_data, pCB, CBSTATUS_STENCIL_READ_MASK_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
205311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                  DRAWSTATE_STENCIL_NOT_BOUND, "Dynamic stencil read mask state not set for this command buffer");
205411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        result |= validate_status(dev_data, pCB, CBSTATUS_STENCIL_WRITE_MASK_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
205511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                  DRAWSTATE_STENCIL_NOT_BOUND, "Dynamic stencil write mask state not set for this command buffer");
205611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        result |= validate_status(dev_data, pCB, CBSTATUS_STENCIL_REFERENCE_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
205711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                  DRAWSTATE_STENCIL_NOT_BOUND, "Dynamic stencil reference state not set for this command buffer");
205811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
205911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (indexedDraw) {
206011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        result |= validate_status(dev_data, pCB, CBSTATUS_INDEX_BUFFER_BOUND, VK_DEBUG_REPORT_ERROR_BIT_EXT,
206111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                  DRAWSTATE_INDEX_BUFFER_NOT_BOUND,
206211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                  "Index buffer object not bound to this command buffer when Indexed Draw attempted");
206311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
206411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
206511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
206611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
206711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Verify attachment reference compatibility according to spec
206811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//  If one array is larger, treat missing elements of shorter array as VK_ATTACHMENT_UNUSED & other array much match this
206911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//  If both AttachmentReference arrays have requested index, check their corresponding AttachementDescriptions
207011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//   to make sure that format and samples counts match.
207111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//  If not, they are not compatible.
207211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool attachment_references_compatible(const uint32_t index, const VkAttachmentReference *pPrimary,
207311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                             const uint32_t primaryCount, const VkAttachmentDescription *pPrimaryAttachments,
207411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                             const VkAttachmentReference *pSecondary, const uint32_t secondaryCount,
207511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                             const VkAttachmentDescription *pSecondaryAttachments) {
207611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (index >= primaryCount) { // Check secondary as if primary is VK_ATTACHMENT_UNUSED
207711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (VK_ATTACHMENT_UNUSED == pSecondary[index].attachment)
207811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return true;
207911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else if (index >= secondaryCount) { // Check primary as if secondary is VK_ATTACHMENT_UNUSED
208011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (VK_ATTACHMENT_UNUSED == pPrimary[index].attachment)
208111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return true;
208211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else { // format and sample count must match
208311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if ((pPrimaryAttachments[pPrimary[index].attachment].format ==
208411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert             pSecondaryAttachments[pSecondary[index].attachment].format) &&
208511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            (pPrimaryAttachments[pPrimary[index].attachment].samples ==
208611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert             pSecondaryAttachments[pSecondary[index].attachment].samples))
208711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return true;
208811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
208911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Format and sample counts didn't match
209011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return false;
209111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
209211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
209311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// For give primary and secondary RenderPass objects, verify that they're compatible
209411cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool verify_renderpass_compatibility(layer_data *my_data, const VkRenderPass primaryRP, const VkRenderPass secondaryRP,
209511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            string &errorMsg) {
209611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto primary_render_pass = getRenderPass(my_data, primaryRP);
209711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto secondary_render_pass = getRenderPass(my_data, secondaryRP);
209811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
209911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!primary_render_pass) {
210011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        stringstream errorStr;
210111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        errorStr << "invalid VkRenderPass (" << primaryRP << ")";
210211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        errorMsg = errorStr.str();
210311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return false;
210411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
210511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
210611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!secondary_render_pass) {
210711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        stringstream errorStr;
210811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        errorStr << "invalid VkRenderPass (" << secondaryRP << ")";
210911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        errorMsg = errorStr.str();
211011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return false;
211111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
211211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Trivial pass case is exact same RP
211311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (primaryRP == secondaryRP) {
211411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return true;
211511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
211611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    const VkRenderPassCreateInfo *primaryRPCI = primary_render_pass->pCreateInfo;
211711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    const VkRenderPassCreateInfo *secondaryRPCI = secondary_render_pass->pCreateInfo;
211811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (primaryRPCI->subpassCount != secondaryRPCI->subpassCount) {
211911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        stringstream errorStr;
212011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        errorStr << "RenderPass for primary cmdBuffer has " << primaryRPCI->subpassCount
212111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                 << " subpasses but renderPass for secondary cmdBuffer has " << secondaryRPCI->subpassCount << " subpasses.";
212211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        errorMsg = errorStr.str();
212311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return false;
212411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
212511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    uint32_t spIndex = 0;
212611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (spIndex = 0; spIndex < primaryRPCI->subpassCount; ++spIndex) {
212711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // For each subpass, verify that corresponding color, input, resolve & depth/stencil attachment references are compatible
212811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        uint32_t primaryColorCount = primaryRPCI->pSubpasses[spIndex].colorAttachmentCount;
212911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        uint32_t secondaryColorCount = secondaryRPCI->pSubpasses[spIndex].colorAttachmentCount;
213011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        uint32_t colorMax = std::max(primaryColorCount, secondaryColorCount);
213111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t cIdx = 0; cIdx < colorMax; ++cIdx) {
213211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (!attachment_references_compatible(cIdx, primaryRPCI->pSubpasses[spIndex].pColorAttachments, primaryColorCount,
213311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                  primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pColorAttachments,
213411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                  secondaryColorCount, secondaryRPCI->pAttachments)) {
213511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                stringstream errorStr;
213611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                errorStr << "color attachments at index " << cIdx << " of subpass index " << spIndex << " are not compatible.";
213711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                errorMsg = errorStr.str();
213811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                return false;
213911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            } else if (!attachment_references_compatible(cIdx, primaryRPCI->pSubpasses[spIndex].pResolveAttachments,
214011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                         primaryColorCount, primaryRPCI->pAttachments,
214111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                         secondaryRPCI->pSubpasses[spIndex].pResolveAttachments,
214211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                         secondaryColorCount, secondaryRPCI->pAttachments)) {
214311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                stringstream errorStr;
214411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                errorStr << "resolve attachments at index " << cIdx << " of subpass index " << spIndex << " are not compatible.";
214511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                errorMsg = errorStr.str();
214611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                return false;
214711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
214811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
214911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
215011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!attachment_references_compatible(0, primaryRPCI->pSubpasses[spIndex].pDepthStencilAttachment,
215111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                              1, primaryRPCI->pAttachments,
215211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                              secondaryRPCI->pSubpasses[spIndex].pDepthStencilAttachment,
215311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                              1, secondaryRPCI->pAttachments)) {
215411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            stringstream errorStr;
215511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            errorStr << "depth/stencil attachments of subpass index " << spIndex << " are not compatible.";
215611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            errorMsg = errorStr.str();
215711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return false;
215811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
215911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
216011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        uint32_t primaryInputCount = primaryRPCI->pSubpasses[spIndex].inputAttachmentCount;
216111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        uint32_t secondaryInputCount = secondaryRPCI->pSubpasses[spIndex].inputAttachmentCount;
216211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        uint32_t inputMax = std::max(primaryInputCount, secondaryInputCount);
216311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t i = 0; i < inputMax; ++i) {
216411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (!attachment_references_compatible(i, primaryRPCI->pSubpasses[spIndex].pInputAttachments, primaryColorCount,
216511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                  primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pInputAttachments,
216611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                  secondaryColorCount, secondaryRPCI->pAttachments)) {
216711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                stringstream errorStr;
216811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                errorStr << "input attachments at index " << i << " of subpass index " << spIndex << " are not compatible.";
216911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                errorMsg = errorStr.str();
217011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                return false;
217111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
217211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
217311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
217411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return true;
217511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
217611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
217711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// For given cvdescriptorset::DescriptorSet, verify that its Set is compatible w/ the setLayout corresponding to
217811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// pipelineLayout[layoutIndex]
217911cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool verify_set_layout_compatibility(layer_data *my_data, const cvdescriptorset::DescriptorSet *pSet,
218011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            const VkPipelineLayout layout, const uint32_t layoutIndex, string &errorMsg) {
218111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto pipeline_layout = getPipelineLayout(my_data, layout);
218211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!pipeline_layout) {
218311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        stringstream errorStr;
218411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        errorStr << "invalid VkPipelineLayout (" << layout << ")";
218511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        errorMsg = errorStr.str();
218611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return false;
218711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
218811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (layoutIndex >= pipeline_layout->descriptorSetLayouts.size()) {
218911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        stringstream errorStr;
219011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        errorStr << "VkPipelineLayout (" << layout << ") only contains " << pipeline_layout->descriptorSetLayouts.size()
219111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                 << " setLayouts corresponding to sets 0-" << pipeline_layout->descriptorSetLayouts.size() - 1
219211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                 << ", but you're attempting to bind set to index " << layoutIndex;
219311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        errorMsg = errorStr.str();
219411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return false;
219511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
219611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto layout_node = pipeline_layout->setLayouts[layoutIndex];
219711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return pSet->IsCompatible(layout_node, &errorMsg);
219811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
219911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
220011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Validate that data for each specialization entry is fully contained within the buffer.
220111cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validate_specialization_offsets(debug_report_data *report_data, VkPipelineShaderStageCreateInfo const *info) {
220211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool pass = true;
220311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
220411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkSpecializationInfo const *spec = info->pSpecializationInfo;
220511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
220611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (spec) {
220711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (auto i = 0u; i < spec->mapEntryCount; i++) {
220811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (spec->pMapEntries[i].offset + spec->pMapEntries[i].size > spec->dataSize) {
220911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
221011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            /*dev*/ 0, __LINE__, SHADER_CHECKER_BAD_SPECIALIZATION, "SC",
221111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "Specialization entry %u (for constant id %u) references memory outside provided "
221211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "specialization data (bytes %u.." PRINTF_SIZE_T_SPECIFIER "; " PRINTF_SIZE_T_SPECIFIER
221311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            " bytes provided)",
221411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            i, spec->pMapEntries[i].constantID, spec->pMapEntries[i].offset,
221511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            spec->pMapEntries[i].offset + spec->pMapEntries[i].size - 1, spec->dataSize)) {
221611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
221711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    pass = false;
221811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
221911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
222011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
222111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
222211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
222311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return pass;
222411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
222511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
222611cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool descriptor_type_match(shader_module const *module, uint32_t type_id,
222711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                  VkDescriptorType descriptor_type, unsigned &descriptor_count) {
222811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto type = module->get_def(type_id);
222911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
223011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    descriptor_count = 1;
223111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
223211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    /* Strip off any array or ptrs. Where we remove array levels, adjust the
223311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert     * descriptor count for each dimension. */
223411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    while (type.opcode() == spv::OpTypeArray || type.opcode() == spv::OpTypePointer) {
223511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (type.opcode() == spv::OpTypeArray) {
223611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            descriptor_count *= get_constant_value(module, type.word(3));
223711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            type = module->get_def(type.word(2));
223811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
223911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        else {
224011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            type = module->get_def(type.word(3));
224111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
224211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
224311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
224411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    switch (type.opcode()) {
224511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::OpTypeStruct: {
224611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (auto insn : *module) {
224711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (insn.opcode() == spv::OpDecorate && insn.word(1) == type.word(1)) {
224811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (insn.word(2) == spv::DecorationBlock) {
224911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    return descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ||
225011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                           descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
225111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                } else if (insn.word(2) == spv::DecorationBufferBlock) {
225211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ||
225311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                           descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
225411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
225511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
225611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
225711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
225811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        /* Invalid */
225911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return false;
226011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
226111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
226211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::OpTypeSampler:
226311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return descriptor_type == VK_DESCRIPTOR_TYPE_SAMPLER;
226411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
226511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::OpTypeSampledImage:
226611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) {
226711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            /* Slight relaxation for some GLSL historical madness: samplerBuffer
226811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert             * doesn't really have a sampler, and a texel buffer descriptor
226911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert             * doesn't really provide one. Allow this slight mismatch.
227011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert             */
227111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            auto image_type = module->get_def(type.word(2));
227211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            auto dim = image_type.word(3);
227311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            auto sampled = image_type.word(7);
227411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return dim == spv::DimBuffer && sampled == 1;
227511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
227611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
227711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
227811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case spv::OpTypeImage: {
227911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        /* Many descriptor types backing image types-- depends on dimension
228011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert         * and whether the image will be used with a sampler. SPIRV for
228111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert         * Vulkan requires that sampled be 1 or 2 -- leaving the decision to
228211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert         * runtime is unacceptable.
228311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert         */
228411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto dim = type.word(3);
228511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto sampled = type.word(7);
228611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
228711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (dim == spv::DimSubpassData) {
228811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return descriptor_type == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
228911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else if (dim == spv::DimBuffer) {
229011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (sampled == 1) {
229111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                return descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
229211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            } else {
229311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
229411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
229511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else if (sampled == 1) {
229611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return descriptor_type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
229711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
229811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
229911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
230011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
230111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
230211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    /* We shouldn't really see any other junk types -- but if we do, they're
230311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert     * a mismatch.
230411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert     */
230511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    default:
230611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return false; /* Mismatch */
230711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
230811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
230911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
231011cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool require_feature(debug_report_data *report_data, VkBool32 feature, char const *feature_name) {
231111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!feature) {
231211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
231311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    __LINE__, SHADER_CHECKER_FEATURE_NOT_ENABLED, "SC",
231411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    "Shader requires VkPhysicalDeviceFeatures::%s but is not "
231511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    "enabled on the device",
231611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    feature_name)) {
231711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return false;
231811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
231911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
232011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
232111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return true;
232211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
232311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
232411cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validate_shader_capabilities(debug_report_data *report_data, shader_module const *src,
232511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         VkPhysicalDeviceFeatures const *enabledFeatures) {
232611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool pass = true;
232711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
232811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
232911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto insn : *src) {
233011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (insn.opcode() == spv::OpCapability) {
233111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            switch (insn.word(1)) {
233211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case spv::CapabilityMatrix:
233311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case spv::CapabilityShader:
233411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case spv::CapabilityInputAttachment:
233511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case spv::CapabilitySampled1D:
233611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case spv::CapabilityImage1D:
233711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case spv::CapabilitySampledBuffer:
233811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case spv::CapabilityImageBuffer:
233911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case spv::CapabilityImageQuery:
234011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case spv::CapabilityDerivativeControl:
234111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                // Always supported by a Vulkan 1.0 implementation -- no feature bits.
234211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
234311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
234411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case spv::CapabilityGeometry:
234511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pass &= require_feature(report_data, enabledFeatures->geometryShader, "geometryShader");
234611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
234711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
234811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case spv::CapabilityTessellation:
234911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pass &= require_feature(report_data, enabledFeatures->tessellationShader, "tessellationShader");
235011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
235111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
235211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case spv::CapabilityFloat64:
235311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pass &= require_feature(report_data, enabledFeatures->shaderFloat64, "shaderFloat64");
235411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
235511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
235611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case spv::CapabilityInt64:
235711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pass &= require_feature(report_data, enabledFeatures->shaderInt64, "shaderInt64");
235811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
235911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
236011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case spv::CapabilityTessellationPointSize:
236111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case spv::CapabilityGeometryPointSize:
236211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pass &= require_feature(report_data, enabledFeatures->shaderTessellationAndGeometryPointSize,
236311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        "shaderTessellationAndGeometryPointSize");
236411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
236511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
236611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case spv::CapabilityImageGatherExtended:
236711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pass &= require_feature(report_data, enabledFeatures->shaderImageGatherExtended, "shaderImageGatherExtended");
236811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
236911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
237011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case spv::CapabilityStorageImageMultisample:
237111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pass &= require_feature(report_data, enabledFeatures->shaderStorageImageMultisample, "shaderStorageImageMultisample");
237211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
237311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
237411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case spv::CapabilityUniformBufferArrayDynamicIndexing:
237511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pass &= require_feature(report_data, enabledFeatures->shaderUniformBufferArrayDynamicIndexing,
237611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        "shaderUniformBufferArrayDynamicIndexing");
237711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
237811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
237911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case spv::CapabilitySampledImageArrayDynamicIndexing:
238011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pass &= require_feature(report_data, enabledFeatures->shaderSampledImageArrayDynamicIndexing,
238111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        "shaderSampledImageArrayDynamicIndexing");
238211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
238311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
238411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case spv::CapabilityStorageBufferArrayDynamicIndexing:
238511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pass &= require_feature(report_data, enabledFeatures->shaderStorageBufferArrayDynamicIndexing,
238611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        "shaderStorageBufferArrayDynamicIndexing");
238711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
238811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
238911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case spv::CapabilityStorageImageArrayDynamicIndexing:
239011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pass &= require_feature(report_data, enabledFeatures->shaderStorageImageArrayDynamicIndexing,
239111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        "shaderStorageImageArrayDynamicIndexing");
239211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
239311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
239411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case spv::CapabilityClipDistance:
239511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pass &= require_feature(report_data, enabledFeatures->shaderClipDistance, "shaderClipDistance");
239611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
239711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
239811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case spv::CapabilityCullDistance:
239911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pass &= require_feature(report_data, enabledFeatures->shaderCullDistance, "shaderCullDistance");
240011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
240111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
240211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case spv::CapabilityImageCubeArray:
240311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pass &= require_feature(report_data, enabledFeatures->imageCubeArray, "imageCubeArray");
240411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
240511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
240611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case spv::CapabilitySampleRateShading:
240711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pass &= require_feature(report_data, enabledFeatures->sampleRateShading, "sampleRateShading");
240811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
240911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
241011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case spv::CapabilitySparseResidency:
241111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pass &= require_feature(report_data, enabledFeatures->shaderResourceResidency, "shaderResourceResidency");
241211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
241311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
241411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case spv::CapabilityMinLod:
241511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pass &= require_feature(report_data, enabledFeatures->shaderResourceMinLod, "shaderResourceMinLod");
241611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
241711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
241811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case spv::CapabilitySampledCubeArray:
241911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pass &= require_feature(report_data, enabledFeatures->imageCubeArray, "imageCubeArray");
242011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
242111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
242211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case spv::CapabilityImageMSArray:
242311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pass &= require_feature(report_data, enabledFeatures->shaderStorageImageMultisample, "shaderStorageImageMultisample");
242411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
242511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
242611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case spv::CapabilityStorageImageExtendedFormats:
242711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pass &= require_feature(report_data, enabledFeatures->shaderStorageImageExtendedFormats,
242811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        "shaderStorageImageExtendedFormats");
242911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
243011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
243111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case spv::CapabilityInterpolationFunction:
243211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pass &= require_feature(report_data, enabledFeatures->sampleRateShading, "sampleRateShading");
243311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
243411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
243511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case spv::CapabilityStorageImageReadWithoutFormat:
243611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pass &= require_feature(report_data, enabledFeatures->shaderStorageImageReadWithoutFormat,
243711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        "shaderStorageImageReadWithoutFormat");
243811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
243911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
244011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case spv::CapabilityStorageImageWriteWithoutFormat:
244111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pass &= require_feature(report_data, enabledFeatures->shaderStorageImageWriteWithoutFormat,
244211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        "shaderStorageImageWriteWithoutFormat");
244311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
244411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
244511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case spv::CapabilityMultiViewport:
244611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pass &= require_feature(report_data, enabledFeatures->multiViewport, "multiViewport");
244711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
244811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
244911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            default:
245011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
245111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            __LINE__, SHADER_CHECKER_BAD_CAPABILITY, "SC",
245211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "Shader declares capability %u, not supported in Vulkan.",
245311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            insn.word(1)))
245411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    pass = false;
245511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
245611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
245711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
245811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
245911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
246011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return pass;
246111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
246211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
246311cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validate_pipeline_shader_stage(debug_report_data *report_data,
246411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                           VkPipelineShaderStageCreateInfo const *pStage,
246511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                           PIPELINE_NODE *pipeline,
246611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                           shader_module **out_module,
246711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                           spirv_inst_iter *out_entrypoint,
246811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                           VkPhysicalDeviceFeatures const *enabledFeatures,
246911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                           std::unordered_map<VkShaderModule,
247011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                           std::unique_ptr<shader_module>> const &shaderModuleMap) {
247111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool pass = true;
247211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto module_it = shaderModuleMap.find(pStage->module);
247311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto module = *out_module = module_it->second.get();
247411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    pass &= validate_specialization_offsets(report_data, pStage);
247511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
247611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    /* find the entrypoint */
247711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto entrypoint = *out_entrypoint = find_entrypoint(module, pStage->pName, pStage->stage);
247811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (entrypoint == module->end()) {
247911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
248011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    __LINE__, SHADER_CHECKER_MISSING_ENTRYPOINT, "SC",
248111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    "No entrypoint found named `%s` for stage %s", pStage->pName,
248211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    string_VkShaderStageFlagBits(pStage->stage))) {
248311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pass = false;
248411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
248511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
248611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
248711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    /* validate shader capabilities against enabled device features */
248811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    pass &= validate_shader_capabilities(report_data, module, enabledFeatures);
248911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
249011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    /* mark accessible ids */
249111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unordered_set<uint32_t> accessible_ids;
249211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    mark_accessible_ids(module, entrypoint, accessible_ids);
249311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
249411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    /* validate descriptor set layout against what the entrypoint actually uses */
249511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::map<descriptor_slot_t, interface_var> descriptor_uses;
249611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    collect_interface_by_descriptor_slot(report_data, module, accessible_ids, descriptor_uses);
249711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
249811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto pipelineLayout = pipeline->pipelineLayout;
249911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
250011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    /* validate push constant usage */
250111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    pass &= validate_push_constant_usage(report_data, &pipelineLayout->pushConstantRanges,
250211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        module, accessible_ids, pStage->stage);
250311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
250411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    /* validate descriptor use */
250511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto use : descriptor_uses) {
250611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // While validating shaders capture which slots are used by the pipeline
250711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pipeline->active_slots[use.first.first].insert(use.first.second);
250811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
250911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        /* verify given pipelineLayout has requested setLayout with requested binding */
251011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        const auto & binding = get_descriptor_binding(pipelineLayout, use.first);
251111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        unsigned required_descriptor_count;
251211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
251311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!binding) {
251411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
251511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        __LINE__, SHADER_CHECKER_MISSING_DESCRIPTOR, "SC",
251611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "Shader uses descriptor slot %u.%u (used as type `%s`) but not declared in pipeline layout",
251711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        use.first.first, use.first.second, describe_type(module, use.second.type_id).c_str())) {
251811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pass = false;
251911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
252011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else if (~binding->stageFlags & pStage->stage) {
252111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
252211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        /*dev*/ 0, __LINE__, SHADER_CHECKER_DESCRIPTOR_NOT_ACCESSIBLE_FROM_STAGE, "SC",
252311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "Shader uses descriptor slot %u.%u (used "
252411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "as type `%s`) but descriptor not "
252511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "accessible from stage %s",
252611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        use.first.first, use.first.second, describe_type(module, use.second.type_id).c_str(),
252711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        string_VkShaderStageFlagBits(pStage->stage))) {
252811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pass = false;
252911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
253011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else if (!descriptor_type_match(module, use.second.type_id, binding->descriptorType,
253111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                          /*out*/ required_descriptor_count)) {
253211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
253311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        SHADER_CHECKER_DESCRIPTOR_TYPE_MISMATCH, "SC", "Type mismatch on descriptor slot "
253411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                       "%u.%u (used as type `%s`) but "
253511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                       "descriptor of type %s",
253611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        use.first.first, use.first.second, describe_type(module, use.second.type_id).c_str(),
253711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        string_VkDescriptorType(binding->descriptorType))) {
253811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pass = false;
253911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
254011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else if (binding->descriptorCount < required_descriptor_count) {
254111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
254211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        SHADER_CHECKER_DESCRIPTOR_TYPE_MISMATCH, "SC",
254311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "Shader expects at least %u descriptors for binding %u.%u (used as type `%s`) but only %u provided",
254411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        required_descriptor_count, use.first.first, use.first.second,
254511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        describe_type(module, use.second.type_id).c_str(), binding->descriptorCount)) {
254611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pass = false;
254711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
254811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
254911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
255011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
255111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return pass;
255211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
255311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
255411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
255511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Validate that the shaders used by the given pipeline and store the active_slots
255611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//  that are actually used by the pipeline into pPipeline->active_slots
255711cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validate_and_capture_pipeline_shader_state(debug_report_data *report_data, PIPELINE_NODE *pPipeline,
255811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                       VkPhysicalDeviceFeatures const *enabledFeatures,
255911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                       std::unordered_map<VkShaderModule, unique_ptr<shader_module>> const & shaderModuleMap) {
256011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto pCreateInfo = pPipeline->graphicsPipelineCI.ptr();
256111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    int vertex_stage = get_shader_stage_id(VK_SHADER_STAGE_VERTEX_BIT);
256211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    int fragment_stage = get_shader_stage_id(VK_SHADER_STAGE_FRAGMENT_BIT);
256311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
256411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    shader_module *shaders[5];
256511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    memset(shaders, 0, sizeof(shaders));
256611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    spirv_inst_iter entrypoints[5];
256711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    memset(entrypoints, 0, sizeof(entrypoints));
256811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkPipelineVertexInputStateCreateInfo const *vi = 0;
256911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool pass = true;
257011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
257111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) {
257211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto pStage = &pCreateInfo->pStages[i];
257311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto stage_id = get_shader_stage_id(pStage->stage);
257411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pass &= validate_pipeline_shader_stage(report_data, pStage, pPipeline,
257511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                               &shaders[stage_id], &entrypoints[stage_id],
257611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                               enabledFeatures, shaderModuleMap);
257711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
257811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
257911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    vi = pCreateInfo->pVertexInputState;
258011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
258111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (vi) {
258211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pass &= validate_vi_consistency(report_data, vi);
258311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
258411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
258511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (shaders[vertex_stage]) {
258611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pass &= validate_vi_against_vs_inputs(report_data, vi, shaders[vertex_stage], entrypoints[vertex_stage]);
258711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
258811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
258911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    int producer = get_shader_stage_id(VK_SHADER_STAGE_VERTEX_BIT);
259011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    int consumer = get_shader_stage_id(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
259111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
259211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    while (!shaders[producer] && producer != fragment_stage) {
259311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        producer++;
259411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        consumer++;
259511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
259611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
259711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (; producer != fragment_stage && consumer <= fragment_stage; consumer++) {
259811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        assert(shaders[producer]);
259911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (shaders[consumer]) {
260011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pass &= validate_interface_between_stages(report_data,
260111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                      shaders[producer], entrypoints[producer], &shader_stage_attribs[producer],
260211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                      shaders[consumer], entrypoints[consumer], &shader_stage_attribs[consumer]);
260311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
260411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            producer = consumer;
260511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
260611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
260711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
260811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (shaders[fragment_stage] && pPipeline->renderPass) {
260911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pass &= validate_fs_outputs_against_render_pass(report_data, shaders[fragment_stage], entrypoints[fragment_stage],
261011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                        pPipeline->renderPass, pCreateInfo->subpass);
261111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
261211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
261311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return pass;
261411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
261511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
261611cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validate_compute_pipeline(debug_report_data *report_data, PIPELINE_NODE *pPipeline, VkPhysicalDeviceFeatures const *enabledFeatures,
261711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                      std::unordered_map<VkShaderModule, unique_ptr<shader_module>> const & shaderModuleMap) {
261811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto pCreateInfo = pPipeline->computePipelineCI.ptr();
261911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
262011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    shader_module *module;
262111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    spirv_inst_iter entrypoint;
262211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
262311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return validate_pipeline_shader_stage(report_data, &pCreateInfo->stage, pPipeline,
262411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                          &module, &entrypoint, enabledFeatures, shaderModuleMap);
262511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
262611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
262711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Return Set node ptr for specified set or else NULL
262811cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic cvdescriptorset::DescriptorSet *getSetNode(layer_data *my_data, const VkDescriptorSet set) {
262911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (my_data->setMap.find(set) == my_data->setMap.end()) {
263011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return NULL;
263111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
263211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return my_data->setMap[set];
263311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
263411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// For the given command buffer, verify and update the state for activeSetBindingsPairs
263511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//  This includes:
263611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//  1. Verifying that any dynamic descriptor in that set has a valid dynamic offset bound.
263711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//     To be valid, the dynamic offset combined with the offset and range from its
263811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//     descriptor update must not overflow the size of its buffer being updated
263911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//  2. Grow updateImages for given pCB to include any bound STORAGE_IMAGE descriptor images
264011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//  3. Grow updateBuffers for pCB to include buffers from STORAGE*_BUFFER descriptor buffers
264111cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validate_and_update_drawtime_descriptor_state(
264211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data, GLOBAL_CB_NODE *pCB,
264311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    const vector<std::tuple<cvdescriptorset::DescriptorSet *, unordered_set<uint32_t>,
264411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            std::vector<uint32_t> const *>> &activeSetBindingsPairs) {
264511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool result = false;
264611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto set_bindings_pair : activeSetBindingsPairs) {
264711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        cvdescriptorset::DescriptorSet *set_node = std::get<0>(set_bindings_pair);
264811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::string err_str;
264911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!set_node->ValidateDrawState(std::get<1>(set_bindings_pair), *std::get<2>(set_bindings_pair),
265011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         &err_str)) {
265111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // Report error here
265211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            auto set = set_node->GetSet();
265311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            result |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
265411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                              reinterpret_cast<const uint64_t &>(set), __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS",
265511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                              "DS 0x%" PRIxLEAST64 " encountered the following validation error at draw time: %s",
265611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                              reinterpret_cast<const uint64_t &>(set), err_str.c_str());
265711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
265811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        set_node->GetStorageUpdates(std::get<1>(set_bindings_pair), &pCB->updateBuffers, &pCB->updateImages);
265911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
266011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
266111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
266211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// TODO : This is a temp function that naively updates bound storage images and buffers based on which descriptor sets are bound.
266311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//   When validate_and_update_draw_state() handles compute shaders so that active_slots is correct for compute pipelines, this
266411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//   function can be killed and validate_and_update_draw_state() used instead
266511cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void update_shader_storage_images_and_buffers(layer_data *dev_data, GLOBAL_CB_NODE *pCB) {
266611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // For the bound descriptor sets, pull off any storage images and buffers
266711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    //  This may be more than are actually updated depending on which are active, but for now this is a stop-gap for compute
266811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    //  pipelines
266911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto set : pCB->lastBound[VK_PIPELINE_BIND_POINT_COMPUTE].uniqueBoundSets) {
267011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        set->GetAllStorageUpdates(&pCB->updateBuffers, &pCB->updateImages);
267111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
267211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
267311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
267411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// For given pipeline, return number of MSAA samples, or one if MSAA disabled
267511cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic VkSampleCountFlagBits getNumSamples(PIPELINE_NODE const *pipe) {
267611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pipe->graphicsPipelineCI.pMultisampleState != NULL &&
267711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO == pipe->graphicsPipelineCI.pMultisampleState->sType) {
267811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return pipe->graphicsPipelineCI.pMultisampleState->rasterizationSamples;
267911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
268011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return VK_SAMPLE_COUNT_1_BIT;
268111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
268211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
268311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Validate draw-time state related to the PSO
268411cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validatePipelineDrawtimeState(layer_data const *my_data, const GLOBAL_CB_NODE *pCB,
268511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                          const VkPipelineBindPoint pipelineBindPoint, PIPELINE_NODE const *pPipeline) {
268611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
268711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (VK_PIPELINE_BIND_POINT_GRAPHICS == pipelineBindPoint) {
268811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Verify that any MSAA request in PSO matches sample# in bound FB
268911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Skip the check if rasterization is disabled.
269011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!pPipeline->graphicsPipelineCI.pRasterizationState ||
269111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            (pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable == VK_FALSE)) {
269211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            VkSampleCountFlagBits pso_num_samples = getNumSamples(pPipeline);
269311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (pCB->activeRenderPass) {
269411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                const VkRenderPassCreateInfo *render_pass_info = pCB->activeRenderPass->pCreateInfo;
269511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                const VkSubpassDescription *subpass_desc = &render_pass_info->pSubpasses[pCB->activeSubpass];
269611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                VkSampleCountFlagBits subpass_num_samples = VkSampleCountFlagBits(0);
269711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                uint32_t i;
269811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
269911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                const VkPipelineColorBlendStateCreateInfo *color_blend_state = pPipeline->graphicsPipelineCI.pColorBlendState;
270011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if ((color_blend_state != NULL) && (pCB->activeSubpass == pPipeline->graphicsPipelineCI.subpass) &&
270111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    (color_blend_state->attachmentCount != subpass_desc->colorAttachmentCount)) {
270211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skip_call |=
270311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
270411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                reinterpret_cast<const uint64_t &>(pPipeline->pipeline), __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
270511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                "Render pass subpass %u mismatch with blending state defined and blend state attachment "
270611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                "count %u while subpass color attachment count %u in Pipeline (0x%" PRIxLEAST64 ")!  These "
270711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                "must be the same at draw-time.",
270811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                pCB->activeSubpass, color_blend_state->attachmentCount, subpass_desc->colorAttachmentCount,
270911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                reinterpret_cast<const uint64_t &>(pPipeline->pipeline));
271011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
271111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
271211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                for (i = 0; i < subpass_desc->colorAttachmentCount; i++) {
271311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    VkSampleCountFlagBits samples;
271411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
271511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    if (subpass_desc->pColorAttachments[i].attachment == VK_ATTACHMENT_UNUSED)
271611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        continue;
271711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
271811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    samples = render_pass_info->pAttachments[subpass_desc->pColorAttachments[i].attachment].samples;
271911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    if (subpass_num_samples == static_cast<VkSampleCountFlagBits>(0)) {
272011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        subpass_num_samples = samples;
272111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    } else if (subpass_num_samples != samples) {
272211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        subpass_num_samples = static_cast<VkSampleCountFlagBits>(-1);
272311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        break;
272411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    }
272511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
272611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if ((subpass_desc->pDepthStencilAttachment != NULL) &&
272711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    (subpass_desc->pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED)) {
272811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    const VkSampleCountFlagBits samples =
272911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        render_pass_info->pAttachments[subpass_desc->pDepthStencilAttachment->attachment].samples;
273011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    if (subpass_num_samples == static_cast<VkSampleCountFlagBits>(0))
273111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        subpass_num_samples = samples;
273211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    else if (subpass_num_samples != samples)
273311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        subpass_num_samples = static_cast<VkSampleCountFlagBits>(-1);
273411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
273511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
273611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (((subpass_desc->colorAttachmentCount > 0) || (subpass_desc->pDepthStencilAttachment != NULL)) &&
273711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    (pso_num_samples != subpass_num_samples)) {
273811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skip_call |=
273911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
274011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                reinterpret_cast<const uint64_t &>(pPipeline->pipeline), __LINE__, DRAWSTATE_NUM_SAMPLES_MISMATCH, "DS",
274111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                "Num samples mismatch! At draw-time in Pipeline (0x%" PRIxLEAST64
274211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                ") with %u samples while current RenderPass (0x%" PRIxLEAST64 ") w/ %u samples!",
274311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                reinterpret_cast<const uint64_t &>(pPipeline->pipeline), pso_num_samples,
274411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                reinterpret_cast<const uint64_t &>(pCB->activeRenderPass->renderPass), subpass_num_samples);
274511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
274611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            } else {
274711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
274811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                     reinterpret_cast<const uint64_t &>(pPipeline->pipeline), __LINE__, DRAWSTATE_NUM_SAMPLES_MISMATCH, "DS",
274911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                     "No active render pass found at draw-time in Pipeline (0x%" PRIxLEAST64 ")!",
275011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                     reinterpret_cast<const uint64_t &>(pPipeline->pipeline));
275111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
275211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
275311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // TODO : Add more checks here
275411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else {
275511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // TODO : Validate non-gfx pipeline updates
275611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
275711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skip_call;
275811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
275911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
276011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Validate overall state at the time of a draw call
276111cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validate_and_update_draw_state(layer_data *my_data, GLOBAL_CB_NODE *pCB, const bool indexedDraw,
276211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                           const VkPipelineBindPoint bindPoint) {
276311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool result = false;
276411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto const &state = pCB->lastBound[bindPoint];
276511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    PIPELINE_NODE *pPipe = getPipeline(my_data, state.pipeline);
276611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (nullptr == pPipe) {
276711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        result |= log_msg(
276811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
276911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            DRAWSTATE_INVALID_PIPELINE, "DS",
277011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            "At Draw/Dispatch time no valid VkPipeline is bound! This is illegal. Please bind one with vkCmdBindPipeline().");
277111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Early return as any further checks below will be busted w/o a pipeline
277211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (result)
277311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return true;
277411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
277511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // First check flag states
277611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (VK_PIPELINE_BIND_POINT_GRAPHICS == bindPoint)
277711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        result = validate_draw_state_flags(my_data, pCB, pPipe, indexedDraw);
277811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    else {
277911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // First block of code below to validate active sets should eventually
278011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        //  work for the compute case but currently doesn't so return early for now
278111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // TODO : When active sets in compute shaders are correctly parsed,
278211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        //  stop returning early here and handle them in top block below
278311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return result;
278411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
278511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
278611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Now complete other state checks
278711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODO : When Compute shaders are properly parsed, fix this section to validate them as well
278811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (state.pipelineLayout) {
278911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        string errorString;
279011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Need a vector (vs. std::set) of active Sets for dynamicOffset validation in case same set bound w/ different offsets
279111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        vector<std::tuple<cvdescriptorset::DescriptorSet *, unordered_set<uint32_t>, std::vector<uint32_t> const *>> activeSetBindingsPairs;
279211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (auto & setBindingPair : pPipe->active_slots) {
279311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            uint32_t setIndex = setBindingPair.first;
279411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // If valid set is not bound throw an error
279511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if ((state.boundDescriptorSets.size() <= setIndex) || (!state.boundDescriptorSets[setIndex])) {
279611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
279711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                  DRAWSTATE_DESCRIPTOR_SET_NOT_BOUND, "DS",
279811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                  "VkPipeline 0x%" PRIxLEAST64 " uses set #%u but that set is not bound.", (uint64_t)pPipe->pipeline,
279911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                  setIndex);
280011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            } else if (!verify_set_layout_compatibility(my_data, state.boundDescriptorSets[setIndex],
280111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                        pPipe->graphicsPipelineCI.layout, setIndex, errorString)) {
280211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                // Set is bound but not compatible w/ overlapping pipelineLayout from PSO
280311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                VkDescriptorSet setHandle = state.boundDescriptorSets[setIndex]->GetSet();
280411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                result |=
280511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
280611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            (uint64_t)setHandle, __LINE__, DRAWSTATE_PIPELINE_LAYOUTS_INCOMPATIBLE, "DS",
280711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "VkDescriptorSet (0x%" PRIxLEAST64
280811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            ") bound as set #%u is not compatible with overlapping VkPipelineLayout 0x%" PRIxLEAST64 " due to: %s",
280911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            (uint64_t)setHandle, setIndex, (uint64_t)pPipe->graphicsPipelineCI.layout, errorString.c_str());
281011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            } else { // Valid set is bound and layout compatible, validate that it's updated
281111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                // Pull the set node
281211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                cvdescriptorset::DescriptorSet *pSet = state.boundDescriptorSets[setIndex];
281311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                // Save vector of all active sets to verify dynamicOffsets below
281411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                activeSetBindingsPairs.push_back(std::make_tuple(pSet, setBindingPair.second,
281511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                 &state.dynamicOffsets[setIndex]));
281611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                // Make sure set has been updated if it has no immutable samplers
281711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                //  If it has immutable samplers, we'll flag error later as needed depending on binding
281811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (!pSet->IsUpdated()) {
281911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    for (auto binding : setBindingPair.second) {
282011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        if (!pSet->GetImmutableSamplerPtrFromBinding(binding)) {
282111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            result |= log_msg(
282211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
282311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                (uint64_t)pSet->GetSet(), __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS",
282411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                "DS 0x%" PRIxLEAST64 " bound but it was never updated. It is now being used to draw so "
282511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                "this will result in undefined behavior.",
282611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                (uint64_t)pSet->GetSet());
282711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        }
282811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    }
282911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
283011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
283111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
283211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // For given active slots, verify any dynamic descriptors and record updated images & buffers
283311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        result |= validate_and_update_drawtime_descriptor_state(my_data, pCB, activeSetBindingsPairs);
283411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
283511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODO : If/when compute pipelines/shaders are handled above, code below is only for gfx bind poing
283611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    //if (VK_PIPELINE_BIND_POINT_GRAPHICS == bindPoint) {
283711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Verify Vtx binding
283811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pPipe->vertexBindingDescriptions.size() > 0) {
283911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (size_t i = 0; i < pPipe->vertexBindingDescriptions.size(); i++) {
284011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if ((pCB->currentDrawData.buffers.size() < (i + 1)) || (pCB->currentDrawData.buffers[i] == VK_NULL_HANDLE)) {
284111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
284211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                  __LINE__, DRAWSTATE_VTX_INDEX_OUT_OF_BOUNDS, "DS",
284311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                  "The Pipeline State Object (0x%" PRIxLEAST64
284411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                  ") expects that this Command Buffer's vertex binding Index " PRINTF_SIZE_T_SPECIFIER
284511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                  " should be set via vkCmdBindVertexBuffers.",
284611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                  (uint64_t)state.pipeline, i);
284711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
284811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
284911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else {
285011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!pCB->currentDrawData.buffers.empty()) {
285111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0,
285211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                              0, __LINE__, DRAWSTATE_VTX_INDEX_OUT_OF_BOUNDS, "DS",
285311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                              "Vertex buffers are bound to command buffer (0x%" PRIxLEAST64
285411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                              ") but no vertex buffers are attached to this Pipeline State Object (0x%" PRIxLEAST64 ").",
285511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                              (uint64_t)pCB->commandBuffer, (uint64_t)state.pipeline);
285611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
285711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
285811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // If Viewport or scissors are dynamic, verify that dynamic count matches PSO count.
285911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Skip check if rasterization is disabled or there is no viewport.
286011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if ((!pPipe->graphicsPipelineCI.pRasterizationState ||
286111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert         (pPipe->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable == VK_FALSE)) &&
286211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pPipe->graphicsPipelineCI.pViewportState) {
286311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        bool dynViewport = isDynamic(pPipe, VK_DYNAMIC_STATE_VIEWPORT);
286411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        bool dynScissor = isDynamic(pPipe, VK_DYNAMIC_STATE_SCISSOR);
286511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (dynViewport) {
286611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (pCB->viewports.size() != pPipe->graphicsPipelineCI.pViewportState->viewportCount) {
286711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
286811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                  __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS",
286911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                  "Dynamic viewportCount from vkCmdSetViewport() is " PRINTF_SIZE_T_SPECIFIER
287011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                  ", but PSO viewportCount is %u. These counts must match.",
287111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                  pCB->viewports.size(), pPipe->graphicsPipelineCI.pViewportState->viewportCount);
287211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
287311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
287411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (dynScissor) {
287511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (pCB->scissors.size() != pPipe->graphicsPipelineCI.pViewportState->scissorCount) {
287611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
287711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                  __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS",
287811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                  "Dynamic scissorCount from vkCmdSetScissor() is " PRINTF_SIZE_T_SPECIFIER
287911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                  ", but PSO scissorCount is %u. These counts must match.",
288011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                  pCB->scissors.size(), pPipe->graphicsPipelineCI.pViewportState->scissorCount);
288111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
288211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
288311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
288411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    //} // end of "if (VK_PIPELINE_BIND_POINT_GRAPHICS == bindPoint) {" block
288511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
288611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Check general pipeline state that needs to be validated at drawtime
288711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    result |= validatePipelineDrawtimeState(my_data, pCB, bindPoint, pPipe);
288811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
288911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
289011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
289111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
289211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Validate HW line width capabilities prior to setting requested line width.
289311cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool verifyLineWidth(layer_data *my_data, DRAW_STATE_ERROR dsError, const uint64_t &target, float lineWidth) {
289411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
289511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
289611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // First check to see if the physical device supports wide lines.
289711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if ((VK_FALSE == my_data->phys_dev_properties.features.wideLines) && (1.0f != lineWidth)) {
289811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, target, __LINE__,
289911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             dsError, "DS", "Attempt to set lineWidth to %f but physical device wideLines feature "
290011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            "not supported/enabled so lineWidth must be 1.0f!",
290111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             lineWidth);
290211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else {
290311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Otherwise, make sure the width falls in the valid range.
290411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if ((my_data->phys_dev_properties.properties.limits.lineWidthRange[0] > lineWidth) ||
290511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            (my_data->phys_dev_properties.properties.limits.lineWidthRange[1] < lineWidth)) {
290611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, target,
290711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 __LINE__, dsError, "DS", "Attempt to set lineWidth to %f but physical device limits line width "
290811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                          "to between [%f, %f]!",
290911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 lineWidth, my_data->phys_dev_properties.properties.limits.lineWidthRange[0],
291011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 my_data->phys_dev_properties.properties.limits.lineWidthRange[1]);
291111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
291211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
291311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
291411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skip_call;
291511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
291611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
291711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Verify that create state for a pipeline is valid
291811cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool verifyPipelineCreateState(layer_data *my_data, const VkDevice device, std::vector<PIPELINE_NODE *> pPipelines,
291911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                      int pipelineIndex) {
292011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
292111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
292211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    PIPELINE_NODE *pPipeline = pPipelines[pipelineIndex];
292311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
292411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // If create derivative bit is set, check that we've specified a base
292511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // pipeline correctly, and that the base pipeline was created to allow
292611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // derivatives.
292711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pPipeline->graphicsPipelineCI.flags & VK_PIPELINE_CREATE_DERIVATIVE_BIT) {
292811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        PIPELINE_NODE *pBasePipeline = nullptr;
292911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!((pPipeline->graphicsPipelineCI.basePipelineHandle != VK_NULL_HANDLE) ^
293011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert              (pPipeline->graphicsPipelineCI.basePipelineIndex != -1))) {
293111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
293211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
293311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                "Invalid Pipeline CreateInfo: exactly one of base pipeline index and handle must be specified");
293411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else if (pPipeline->graphicsPipelineCI.basePipelineIndex != -1) {
293511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (pPipeline->graphicsPipelineCI.basePipelineIndex >= pipelineIndex) {
293611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skipCall |=
293711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
293811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
293911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "Invalid Pipeline CreateInfo: base pipeline must occur earlier in array than derivative pipeline.");
294011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            } else {
294111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pBasePipeline = pPipelines[pPipeline->graphicsPipelineCI.basePipelineIndex];
294211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
294311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else if (pPipeline->graphicsPipelineCI.basePipelineHandle != VK_NULL_HANDLE) {
294411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pBasePipeline = getPipeline(my_data, pPipeline->graphicsPipelineCI.basePipelineHandle);
294511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
294611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
294711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (pBasePipeline && !(pBasePipeline->graphicsPipelineCI.flags & VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT)) {
294811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
294911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
295011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                "Invalid Pipeline CreateInfo: base pipeline does not allow derivatives.");
295111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
295211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
295311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
295411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pPipeline->graphicsPipelineCI.pColorBlendState != NULL) {
295511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!my_data->phys_dev_properties.features.independentBlend) {
295611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (pPipeline->attachments.size() > 1) {
295711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                VkPipelineColorBlendAttachmentState *pAttachments = &pPipeline->attachments[0];
295811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                for (size_t i = 1; i < pPipeline->attachments.size(); i++) {
295911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    if ((pAttachments[0].blendEnable != pAttachments[i].blendEnable) ||
296011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        (pAttachments[0].srcColorBlendFactor != pAttachments[i].srcColorBlendFactor) ||
296111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        (pAttachments[0].dstColorBlendFactor != pAttachments[i].dstColorBlendFactor) ||
296211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        (pAttachments[0].colorBlendOp != pAttachments[i].colorBlendOp) ||
296311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        (pAttachments[0].srcAlphaBlendFactor != pAttachments[i].srcAlphaBlendFactor) ||
296411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        (pAttachments[0].dstAlphaBlendFactor != pAttachments[i].dstAlphaBlendFactor) ||
296511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        (pAttachments[0].alphaBlendOp != pAttachments[i].alphaBlendOp) ||
296611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        (pAttachments[0].colorWriteMask != pAttachments[i].colorWriteMask)) {
296711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        skipCall |=
296811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
296911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            DRAWSTATE_INDEPENDENT_BLEND, "DS", "Invalid Pipeline CreateInfo: If independent blend feature not "
297011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "enabled, all elements of pAttachments must be identical");
297111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    }
297211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
297311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
297411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
297511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!my_data->phys_dev_properties.features.logicOp &&
297611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            (pPipeline->graphicsPipelineCI.pColorBlendState->logicOpEnable != VK_FALSE)) {
297711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |=
297811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
297911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        DRAWSTATE_DISABLED_LOGIC_OP, "DS",
298011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "Invalid Pipeline CreateInfo: If logic operations feature not enabled, logicOpEnable must be VK_FALSE");
298111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
298211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if ((pPipeline->graphicsPipelineCI.pColorBlendState->logicOpEnable == VK_TRUE) &&
298311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            ((pPipeline->graphicsPipelineCI.pColorBlendState->logicOp < VK_LOGIC_OP_CLEAR) ||
298411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert             (pPipeline->graphicsPipelineCI.pColorBlendState->logicOp > VK_LOGIC_OP_SET))) {
298511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |=
298611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
298711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        DRAWSTATE_INVALID_LOGIC_OP, "DS",
298811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "Invalid Pipeline CreateInfo: If logicOpEnable is VK_TRUE, logicOp must be a valid VkLogicOp value");
298911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
299011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
299111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
299211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Ensure the subpass index is valid. If not, then validate_and_capture_pipeline_shader_state
299311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // produces nonsense errors that confuse users. Other layers should already
299411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // emit errors for renderpass being invalid.
299511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto renderPass = getRenderPass(my_data, pPipeline->graphicsPipelineCI.renderPass);
299611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (renderPass &&
299711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pPipeline->graphicsPipelineCI.subpass >= renderPass->pCreateInfo->subpassCount) {
299811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
299911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", "Invalid Pipeline CreateInfo State: Subpass index %u "
300011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                           "is out of range for this renderpass (0..%u)",
300111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            pPipeline->graphicsPipelineCI.subpass, renderPass->pCreateInfo->subpassCount - 1);
300211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
300311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
300411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!validate_and_capture_pipeline_shader_state(my_data->report_data, pPipeline, &my_data->phys_dev_properties.features,
300511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                    my_data->shaderModuleMap)) {
300611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall = true;
300711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
300811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Each shader's stage must be unique
300911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pPipeline->duplicate_shaders) {
301011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t stage = VK_SHADER_STAGE_VERTEX_BIT; stage & VK_SHADER_STAGE_ALL_GRAPHICS; stage <<= 1) {
301111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (pPipeline->duplicate_shaders & stage) {
301211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
301311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    __LINE__, DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
301411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    "Invalid Pipeline CreateInfo State: Multiple shaders provided for stage %s",
301511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    string_VkShaderStageFlagBits(VkShaderStageFlagBits(stage)));
301611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
301711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
301811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
301911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // VS is required
302011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!(pPipeline->active_shaders & VK_SHADER_STAGE_VERTEX_BIT)) {
302111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |=
302211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
302311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", "Invalid Pipeline CreateInfo State: Vtx Shader required");
302411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
302511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Either both or neither TC/TE shaders should be defined
302611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (((pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) == 0) !=
302711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        ((pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) == 0)) {
302811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
302911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
303011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "Invalid Pipeline CreateInfo State: TE and TC shaders must be included or excluded as a pair");
303111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
303211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Compute shaders should be specified independent of Gfx shaders
303311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if ((pPipeline->active_shaders & VK_SHADER_STAGE_COMPUTE_BIT) &&
303411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        (pPipeline->active_shaders &
303511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert         (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT |
303611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert          VK_SHADER_STAGE_GEOMETRY_BIT | VK_SHADER_STAGE_FRAGMENT_BIT))) {
303711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
303811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
303911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "Invalid Pipeline CreateInfo State: Do not specify Compute Shader for Gfx Pipeline");
304011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
304111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive topology is only valid for tessellation pipelines.
304211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Mismatching primitive topology and tessellation fails graphics pipeline creation.
304311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pPipeline->active_shaders & (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) &&
304411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        (!pPipeline->graphicsPipelineCI.pInputAssemblyState ||
304511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert         pPipeline->graphicsPipelineCI.pInputAssemblyState->topology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST)) {
304611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
304711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", "Invalid Pipeline CreateInfo State: "
304811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                           "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST must be set as IA "
304911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                           "topology for tessellation pipelines");
305011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
305111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pPipeline->graphicsPipelineCI.pInputAssemblyState &&
305211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pPipeline->graphicsPipelineCI.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) {
305311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (~pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) {
305411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
305511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", "Invalid Pipeline CreateInfo State: "
305611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                               "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive "
305711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                               "topology is only valid for tessellation pipelines");
305811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
305911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!pPipeline->graphicsPipelineCI.pTessellationState) {
306011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
306111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
306211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                "Invalid Pipeline CreateInfo State: "
306311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                "pTessellationState is NULL when VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive "
306411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                "topology used. pTessellationState must not be NULL in this case.");
306511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else if (!pPipeline->graphicsPipelineCI.pTessellationState->patchControlPoints ||
306611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                   (pPipeline->graphicsPipelineCI.pTessellationState->patchControlPoints > 32)) {
306711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
306811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", "Invalid Pipeline CreateInfo State: "
306911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                               "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive "
307011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                               "topology used with patchControlPoints value %u."
307111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                               " patchControlPoints should be >0 and <=32.",
307211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                pPipeline->graphicsPipelineCI.pTessellationState->patchControlPoints);
307311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
307411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
307511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // If a rasterization state is provided, make sure that the line width conforms to the HW.
307611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pPipeline->graphicsPipelineCI.pRasterizationState) {
307711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!isDynamic(pPipeline, VK_DYNAMIC_STATE_LINE_WIDTH)) {
307811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= verifyLineWidth(my_data, DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, reinterpret_cast<uint64_t &>(pPipeline),
307911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        pPipeline->graphicsPipelineCI.pRasterizationState->lineWidth);
308011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
308111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
308211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Viewport state must be included if rasterization is enabled.
308311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // If the viewport state is included, the viewport and scissor counts should always match.
308411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // NOTE : Even if these are flagged as dynamic, counts need to be set correctly for shader compiler
308511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!pPipeline->graphicsPipelineCI.pRasterizationState ||
308611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        (pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable == VK_FALSE)) {
308711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!pPipeline->graphicsPipelineCI.pViewportState) {
308811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
308911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", "Gfx Pipeline pViewportState is null. Even if viewport "
309011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                           "and scissors are dynamic PSO must include "
309111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                           "viewportCount and scissorCount in pViewportState.");
309211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else if (pPipeline->graphicsPipelineCI.pViewportState->scissorCount !=
309311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                   pPipeline->graphicsPipelineCI.pViewportState->viewportCount) {
309411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
309511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS",
309611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                "Gfx Pipeline viewport count (%u) must match scissor count (%u).",
309711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                pPipeline->graphicsPipelineCI.pViewportState->viewportCount,
309811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                pPipeline->graphicsPipelineCI.pViewportState->scissorCount);
309911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
310011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // If viewport or scissor are not dynamic, then verify that data is appropriate for count
310111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            bool dynViewport = isDynamic(pPipeline, VK_DYNAMIC_STATE_VIEWPORT);
310211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            bool dynScissor = isDynamic(pPipeline, VK_DYNAMIC_STATE_SCISSOR);
310311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (!dynViewport) {
310411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (pPipeline->graphicsPipelineCI.pViewportState->viewportCount &&
310511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    !pPipeline->graphicsPipelineCI.pViewportState->pViewports) {
310611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
310711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS",
310811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        "Gfx Pipeline viewportCount is %u, but pViewports is NULL. For non-zero viewportCount, you "
310911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        "must either include pViewports data, or include viewport in pDynamicState and set it with "
311011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        "vkCmdSetViewport().",
311111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        pPipeline->graphicsPipelineCI.pViewportState->viewportCount);
311211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
311311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
311411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (!dynScissor) {
311511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (pPipeline->graphicsPipelineCI.pViewportState->scissorCount &&
311611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    !pPipeline->graphicsPipelineCI.pViewportState->pScissors) {
311711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
311811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS",
311911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        "Gfx Pipeline scissorCount is %u, but pScissors is NULL. For non-zero scissorCount, you "
312011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        "must either include pScissors data, or include scissor in pDynamicState and set it with "
312111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        "vkCmdSetScissor().",
312211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        pPipeline->graphicsPipelineCI.pViewportState->scissorCount);
312311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
312411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
312511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
312611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
312711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skipCall;
312811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
312911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
313011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Free the Pipeline nodes
313111cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void deletePipelines(layer_data *my_data) {
313211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (my_data->pipelineMap.size() <= 0)
313311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return;
313411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto &pipe_map_pair : my_data->pipelineMap) {
313511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        delete pipe_map_pair.second;
313611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
313711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    my_data->pipelineMap.clear();
313811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
313911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
314011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Block of code at start here specifically for managing/tracking DSs
314111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
314211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Return Pool node ptr for specified pool or else NULL
314311cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic DESCRIPTOR_POOL_NODE *getPoolNode(layer_data *my_data, const VkDescriptorPool pool) {
314411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (my_data->descriptorPoolMap.find(pool) == my_data->descriptorPoolMap.end()) {
314511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return NULL;
314611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
314711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return my_data->descriptorPoolMap[pool];
314811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
314911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
315011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Return false if update struct is of valid type, otherwise flag error and return code from callback
315111cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validUpdateStruct(layer_data *my_data, const VkDevice device, const GENERIC_HEADER *pUpdateStruct) {
315211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    switch (pUpdateStruct->sType) {
315311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET:
315411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET:
315511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return false;
315611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    default:
315711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
315811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                       DRAWSTATE_INVALID_UPDATE_STRUCT, "DS",
315911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                       "Unexpected UPDATE struct of type %s (value %u) in vkUpdateDescriptors() struct tree",
316011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                       string_VkStructureType(pUpdateStruct->sType), pUpdateStruct->sType);
316111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
316211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
316311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
316411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Set count for given update struct in the last parameter
316511cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic uint32_t getUpdateCount(layer_data *my_data, const VkDevice device, const GENERIC_HEADER *pUpdateStruct) {
316611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    switch (pUpdateStruct->sType) {
316711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET:
316811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return ((VkWriteDescriptorSet *)pUpdateStruct)->descriptorCount;
316911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET:
317011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // TODO : Need to understand this case better and make sure code is correct
317111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return ((VkCopyDescriptorSet *)pUpdateStruct)->descriptorCount;
317211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    default:
317311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return 0;
317411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
317511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
317611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
317711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// For given layout and update, return the first overall index of the layout that is updated
317811cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic uint32_t getUpdateStartIndex(layer_data *my_data, const VkDevice device, const uint32_t binding_start_index,
317911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    const uint32_t arrayIndex, const GENERIC_HEADER *pUpdateStruct) {
318011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return binding_start_index + arrayIndex;
318111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
318211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// For given layout and update, return the last overall index of the layout that is updated
318311cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic uint32_t getUpdateEndIndex(layer_data *my_data, const VkDevice device, const uint32_t binding_start_index,
318411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                  const uint32_t arrayIndex, const GENERIC_HEADER *pUpdateStruct) {
318511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    uint32_t count = getUpdateCount(my_data, device, pUpdateStruct);
318611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return binding_start_index + arrayIndex + count - 1;
318711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
318811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Verify that the descriptor type in the update struct matches what's expected by the layout
318911cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validateUpdateConsistency(layer_data *my_data, const VkDevice device, const VkDescriptorType layout_type,
319011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                      const GENERIC_HEADER *pUpdateStruct, uint32_t startIndex, uint32_t endIndex) {
319111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // First get actual type of update
319211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
319311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkDescriptorType actualType = VK_DESCRIPTOR_TYPE_MAX_ENUM;
319411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    switch (pUpdateStruct->sType) {
319511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET:
319611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        actualType = ((VkWriteDescriptorSet *)pUpdateStruct)->descriptorType;
319711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        break;
319811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET:
319911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        /* no need to validate */
320011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return false;
320111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        break;
320211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    default:
320311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
320411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            DRAWSTATE_INVALID_UPDATE_STRUCT, "DS",
320511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "Unexpected UPDATE struct of type %s (value %u) in vkUpdateDescriptors() struct tree",
320611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            string_VkStructureType(pUpdateStruct->sType), pUpdateStruct->sType);
320711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
320811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall) {
320911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (layout_type != actualType) {
321011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= log_msg(
321111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
321211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                DRAWSTATE_DESCRIPTOR_TYPE_MISMATCH, "DS",
321311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                "Write descriptor update has descriptor type %s that does not match overlapping binding descriptor type of %s!",
321411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                string_VkDescriptorType(actualType), string_VkDescriptorType(layout_type));
321511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
321611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
321711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skipCall;
321811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
321911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//TODO: Consolidate functions
322011cd02dfb91661c65134cac258cf5924270e9d2Dan Albertbool FindLayout(const GLOBAL_CB_NODE *pCB, ImageSubresourcePair imgpair, IMAGE_CMD_BUF_LAYOUT_NODE &node, const VkImageAspectFlags aspectMask) {
322111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *my_data = get_my_data_ptr(get_dispatch_key(pCB->commandBuffer), layer_data_map);
322211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!(imgpair.subresource.aspectMask & aspectMask)) {
322311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return false;
322411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
322511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkImageAspectFlags oldAspectMask = imgpair.subresource.aspectMask;
322611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    imgpair.subresource.aspectMask = aspectMask;
322711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto imgsubIt = pCB->imageLayoutMap.find(imgpair);
322811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (imgsubIt == pCB->imageLayoutMap.end()) {
322911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return false;
323011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
323111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (node.layout != VK_IMAGE_LAYOUT_MAX_ENUM && node.layout != imgsubIt->second.layout) {
323211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
323311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                reinterpret_cast<uint64_t&>(imgpair.image), __LINE__, DRAWSTATE_INVALID_LAYOUT, "DS",
323411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                "Cannot query for VkImage 0x%" PRIx64 " layout when combined aspect mask %d has multiple layout types: %s and %s",
323511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                reinterpret_cast<uint64_t&>(imgpair.image), oldAspectMask, string_VkImageLayout(node.layout), string_VkImageLayout(imgsubIt->second.layout));
323611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
323711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (node.initialLayout != VK_IMAGE_LAYOUT_MAX_ENUM && node.initialLayout != imgsubIt->second.initialLayout) {
323811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
323911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                reinterpret_cast<uint64_t&>(imgpair.image), __LINE__, DRAWSTATE_INVALID_LAYOUT, "DS",
324011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                "Cannot query for VkImage 0x%" PRIx64 " layout when combined aspect mask %d has multiple initial layout types: %s and %s",
324111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                reinterpret_cast<uint64_t&>(imgpair.image), oldAspectMask, string_VkImageLayout(node.initialLayout), string_VkImageLayout(imgsubIt->second.initialLayout));
324211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
324311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    node = imgsubIt->second;
324411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return true;
324511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
324611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
324711cd02dfb91661c65134cac258cf5924270e9d2Dan Albertbool FindLayout(const layer_data *my_data, ImageSubresourcePair imgpair, VkImageLayout &layout, const VkImageAspectFlags aspectMask) {
324811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!(imgpair.subresource.aspectMask & aspectMask)) {
324911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return false;
325011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
325111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkImageAspectFlags oldAspectMask = imgpair.subresource.aspectMask;
325211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    imgpair.subresource.aspectMask = aspectMask;
325311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto imgsubIt = my_data->imageLayoutMap.find(imgpair);
325411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (imgsubIt == my_data->imageLayoutMap.end()) {
325511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return false;
325611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
325711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (layout != VK_IMAGE_LAYOUT_MAX_ENUM && layout != imgsubIt->second.layout) {
325811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
325911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                reinterpret_cast<uint64_t&>(imgpair.image), __LINE__, DRAWSTATE_INVALID_LAYOUT, "DS",
326011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                "Cannot query for VkImage 0x%" PRIx64 " layout when combined aspect mask %d has multiple layout types: %s and %s",
326111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                reinterpret_cast<uint64_t&>(imgpair.image), oldAspectMask, string_VkImageLayout(layout), string_VkImageLayout(imgsubIt->second.layout));
326211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
326311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layout = imgsubIt->second.layout;
326411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return true;
326511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
326611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
326711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// find layout(s) on the cmd buf level
326811cd02dfb91661c65134cac258cf5924270e9d2Dan Albertbool FindLayout(const GLOBAL_CB_NODE *pCB, VkImage image, VkImageSubresource range, IMAGE_CMD_BUF_LAYOUT_NODE &node) {
326911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    ImageSubresourcePair imgpair = {image, true, range};
327011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    node = IMAGE_CMD_BUF_LAYOUT_NODE(VK_IMAGE_LAYOUT_MAX_ENUM, VK_IMAGE_LAYOUT_MAX_ENUM);
327111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    FindLayout(pCB, imgpair, node, VK_IMAGE_ASPECT_COLOR_BIT);
327211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    FindLayout(pCB, imgpair, node, VK_IMAGE_ASPECT_DEPTH_BIT);
327311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    FindLayout(pCB, imgpair, node, VK_IMAGE_ASPECT_STENCIL_BIT);
327411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    FindLayout(pCB, imgpair, node, VK_IMAGE_ASPECT_METADATA_BIT);
327511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (node.layout == VK_IMAGE_LAYOUT_MAX_ENUM) {
327611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        imgpair = {image, false, VkImageSubresource()};
327711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto imgsubIt = pCB->imageLayoutMap.find(imgpair);
327811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (imgsubIt == pCB->imageLayoutMap.end())
327911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return false;
328011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        node = imgsubIt->second;
328111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
328211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return true;
328311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
328411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
328511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// find layout(s) on the global level
328611cd02dfb91661c65134cac258cf5924270e9d2Dan Albertbool FindLayout(const layer_data *my_data, ImageSubresourcePair imgpair, VkImageLayout &layout) {
328711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layout = VK_IMAGE_LAYOUT_MAX_ENUM;
328811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    FindLayout(my_data, imgpair, layout, VK_IMAGE_ASPECT_COLOR_BIT);
328911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    FindLayout(my_data, imgpair, layout, VK_IMAGE_ASPECT_DEPTH_BIT);
329011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    FindLayout(my_data, imgpair, layout, VK_IMAGE_ASPECT_STENCIL_BIT);
329111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    FindLayout(my_data, imgpair, layout, VK_IMAGE_ASPECT_METADATA_BIT);
329211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (layout == VK_IMAGE_LAYOUT_MAX_ENUM) {
329311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        imgpair = {imgpair.image, false, VkImageSubresource()};
329411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto imgsubIt = my_data->imageLayoutMap.find(imgpair);
329511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (imgsubIt == my_data->imageLayoutMap.end())
329611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return false;
329711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        layout = imgsubIt->second.layout;
329811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
329911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return true;
330011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
330111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
330211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertbool FindLayout(const layer_data *my_data, VkImage image, VkImageSubresource range, VkImageLayout &layout) {
330311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    ImageSubresourcePair imgpair = {image, true, range};
330411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return FindLayout(my_data, imgpair, layout);
330511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
330611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
330711cd02dfb91661c65134cac258cf5924270e9d2Dan Albertbool FindLayouts(const layer_data *my_data, VkImage image, std::vector<VkImageLayout> &layouts) {
330811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto sub_data = my_data->imageSubresourceMap.find(image);
330911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (sub_data == my_data->imageSubresourceMap.end())
331011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return false;
331111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto imgIt = my_data->imageMap.find(image);
331211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (imgIt == my_data->imageMap.end())
331311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return false;
331411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool ignoreGlobal = false;
331511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODO: Make this robust for >1 aspect mask. Now it will just say ignore
331611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // potential errors in this case.
331711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (sub_data->second.size() >= (imgIt->second.createInfo.arrayLayers * imgIt->second.createInfo.mipLevels + 1)) {
331811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        ignoreGlobal = true;
331911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
332011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto imgsubpair : sub_data->second) {
332111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (ignoreGlobal && !imgsubpair.hasSubresource)
332211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            continue;
332311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto img_data = my_data->imageLayoutMap.find(imgsubpair);
332411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (img_data != my_data->imageLayoutMap.end()) {
332511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            layouts.push_back(img_data->second.layout);
332611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
332711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
332811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return true;
332911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
333011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
333111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Set the layout on the global level
333211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertvoid SetLayout(layer_data *my_data, ImageSubresourcePair imgpair, const VkImageLayout &layout) {
333311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkImage &image = imgpair.image;
333411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODO (mlentine): Maybe set format if new? Not used atm.
333511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    my_data->imageLayoutMap[imgpair].layout = layout;
333611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODO (mlentine): Maybe make vector a set?
333711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto subresource = std::find(my_data->imageSubresourceMap[image].begin(), my_data->imageSubresourceMap[image].end(), imgpair);
333811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (subresource == my_data->imageSubresourceMap[image].end()) {
333911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        my_data->imageSubresourceMap[image].push_back(imgpair);
334011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
334111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
334211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
334311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Set the layout on the cmdbuf level
334411cd02dfb91661c65134cac258cf5924270e9d2Dan Albertvoid SetLayout(GLOBAL_CB_NODE *pCB, ImageSubresourcePair imgpair, const IMAGE_CMD_BUF_LAYOUT_NODE &node) {
334511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    pCB->imageLayoutMap[imgpair] = node;
334611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODO (mlentine): Maybe make vector a set?
334711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto subresource =
334811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::find(pCB->imageSubresourceMap[imgpair.image].begin(), pCB->imageSubresourceMap[imgpair.image].end(), imgpair);
334911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (subresource == pCB->imageSubresourceMap[imgpair.image].end()) {
335011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->imageSubresourceMap[imgpair.image].push_back(imgpair);
335111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
335211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
335311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
335411cd02dfb91661c65134cac258cf5924270e9d2Dan Albertvoid SetLayout(GLOBAL_CB_NODE *pCB, ImageSubresourcePair imgpair, const VkImageLayout &layout) {
335511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODO (mlentine): Maybe make vector a set?
335611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (std::find(pCB->imageSubresourceMap[imgpair.image].begin(), pCB->imageSubresourceMap[imgpair.image].end(), imgpair) !=
335711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->imageSubresourceMap[imgpair.image].end()) {
335811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->imageLayoutMap[imgpair].layout = layout;
335911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else {
336011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // TODO (mlentine): Could be expensive and might need to be removed.
336111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        assert(imgpair.hasSubresource);
336211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        IMAGE_CMD_BUF_LAYOUT_NODE node;
336311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!FindLayout(pCB, imgpair.image, imgpair.subresource, node)) {
336411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            node.initialLayout = layout;
336511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
336611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        SetLayout(pCB, imgpair, {node.initialLayout, layout});
336711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
336811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
336911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
337011cd02dfb91661c65134cac258cf5924270e9d2Dan Alberttemplate <class OBJECT, class LAYOUT>
337111cd02dfb91661c65134cac258cf5924270e9d2Dan Albertvoid SetLayout(OBJECT *pObject, ImageSubresourcePair imgpair, const LAYOUT &layout, VkImageAspectFlags aspectMask) {
337211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (imgpair.subresource.aspectMask & aspectMask) {
337311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        imgpair.subresource.aspectMask = aspectMask;
337411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        SetLayout(pObject, imgpair, layout);
337511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
337611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
337711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
337811cd02dfb91661c65134cac258cf5924270e9d2Dan Alberttemplate <class OBJECT, class LAYOUT>
337911cd02dfb91661c65134cac258cf5924270e9d2Dan Albertvoid SetLayout(OBJECT *pObject, VkImage image, VkImageSubresource range, const LAYOUT &layout) {
338011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    ImageSubresourcePair imgpair = {image, true, range};
338111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    SetLayout(pObject, imgpair, layout, VK_IMAGE_ASPECT_COLOR_BIT);
338211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    SetLayout(pObject, imgpair, layout, VK_IMAGE_ASPECT_DEPTH_BIT);
338311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    SetLayout(pObject, imgpair, layout, VK_IMAGE_ASPECT_STENCIL_BIT);
338411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    SetLayout(pObject, imgpair, layout, VK_IMAGE_ASPECT_METADATA_BIT);
338511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
338611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
338711cd02dfb91661c65134cac258cf5924270e9d2Dan Alberttemplate <class OBJECT, class LAYOUT> void SetLayout(OBJECT *pObject, VkImage image, const LAYOUT &layout) {
338811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    ImageSubresourcePair imgpair = {image, false, VkImageSubresource()};
338911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    SetLayout(pObject, image, imgpair, layout);
339011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
339111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
339211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertvoid SetLayout(const layer_data *dev_data, GLOBAL_CB_NODE *pCB, VkImageView imageView, const VkImageLayout &layout) {
339311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto image_view_data = dev_data->imageViewMap.find(imageView);
339411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    assert(image_view_data != dev_data->imageViewMap.end());
339511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    const VkImage &image = image_view_data->second.image;
339611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    const VkImageSubresourceRange &subRange = image_view_data->second.subresourceRange;
339711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODO: Do not iterate over every possibility - consolidate where possible
339811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t j = 0; j < subRange.levelCount; j++) {
339911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        uint32_t level = subRange.baseMipLevel + j;
340011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t k = 0; k < subRange.layerCount; k++) {
340111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            uint32_t layer = subRange.baseArrayLayer + k;
340211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            VkImageSubresource sub = {subRange.aspectMask, level, layer};
340311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            SetLayout(pCB, image, sub, layout);
340411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
340511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
340611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
340711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
340811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Validate that given set is valid and that it's not being used by an in-flight CmdBuffer
340911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// func_str is the name of the calling function
341011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Return false if no errors occur
341111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Return true if validation error occurs and callback returns true (to skip upcoming API call down the chain)
341211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validateIdleDescriptorSet(const layer_data *my_data, VkDescriptorSet set, std::string func_str) {
341311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
341411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto set_node = my_data->setMap.find(set);
341511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (set_node == my_data->setMap.end()) {
341611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
341711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             (uint64_t)(set), __LINE__, DRAWSTATE_DOUBLE_DESTROY, "DS",
341811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             "Cannot call %s() on descriptor set 0x%" PRIxLEAST64 " that has not been allocated.", func_str.c_str(),
341911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             (uint64_t)(set));
342011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else {
342111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (set_node->second->in_use.load()) {
342211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
342311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)(set), __LINE__, DRAWSTATE_OBJECT_INUSE,
342411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 "DS", "Cannot call %s() on descriptor set 0x%" PRIxLEAST64 " that is in use by a command buffer.",
342511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 func_str.c_str(), (uint64_t)(set));
342611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
342711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
342811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skip_call;
342911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
343011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
343111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Free the descriptor set, remove it from setMap and invalidate any cmd buffers that it was bound to
343211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void freeDescriptorSet(layer_data *dev_data, cvdescriptorset::DescriptorSet *descriptor_set) {
343311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    dev_data->setMap.erase(descriptor_set->GetSet());
343411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    delete descriptor_set;
343511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
343611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Free all DS Pools including their Sets & related sub-structs
343711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// NOTE : Calls to this function should be wrapped in mutex
343811cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void deletePools(layer_data *my_data) {
343911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (my_data->descriptorPoolMap.size() <= 0)
344011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return;
344111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto ii = my_data->descriptorPoolMap.begin(); ii != my_data->descriptorPoolMap.end(); ++ii) {
344211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Remove this pools' sets from setMap and delete them
344311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (auto ds : (*ii).second->sets) {
344411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            freeDescriptorSet(my_data, ds);
344511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
344611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        (*ii).second->sets.clear();
344711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
344811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    my_data->descriptorPoolMap.clear();
344911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
345011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
345111cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void clearDescriptorPool(layer_data *my_data, const VkDevice device, const VkDescriptorPool pool,
345211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                VkDescriptorPoolResetFlags flags) {
345311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    DESCRIPTOR_POOL_NODE *pPool = getPoolNode(my_data, pool);
345411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!pPool) {
345511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
345611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                (uint64_t)pool, __LINE__, DRAWSTATE_INVALID_POOL, "DS",
345711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                "Unable to find pool node for pool 0x%" PRIxLEAST64 " specified in vkResetDescriptorPool() call", (uint64_t)pool);
345811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else {
345911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // TODO: validate flags
346011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // For every set off of this pool, clear it, remove from setMap, and free cvdescriptorset::DescriptorSet
346111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (auto ds : pPool->sets) {
346211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            freeDescriptorSet(my_data, ds);
346311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
346411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pPool->sets.clear();
346511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Reset available count for each type and available sets for this pool
346611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t i = 0; i < pPool->availableDescriptorTypeCount.size(); ++i) {
346711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pPool->availableDescriptorTypeCount[i] = pPool->maxDescriptorTypeCount[i];
346811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
346911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pPool->availableSets = pPool->maxSets;
347011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
347111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
347211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
347311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// For given CB object, fetch associated CB Node from map
347411cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic GLOBAL_CB_NODE *getCBNode(layer_data const *my_data, const VkCommandBuffer cb) {
347511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto it = my_data->commandBufferMap.find(cb);
347611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (it == my_data->commandBufferMap.end()) {
347711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
347811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                reinterpret_cast<const uint64_t &>(cb), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
347911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                "Attempt to use CommandBuffer 0x%" PRIxLEAST64 " that doesn't exist!", (uint64_t)(cb));
348011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return NULL;
348111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
348211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return it->second;
348311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
348411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Free all CB Nodes
348511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// NOTE : Calls to this function should be wrapped in mutex
348611cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void deleteCommandBuffers(layer_data *my_data) {
348711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (my_data->commandBufferMap.empty()) {
348811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return;
348911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
349011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto ii = my_data->commandBufferMap.begin(); ii != my_data->commandBufferMap.end(); ++ii) {
349111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        delete (*ii).second;
349211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
349311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    my_data->commandBufferMap.clear();
349411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
349511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
349611cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool report_error_no_cb_begin(const layer_data *dev_data, const VkCommandBuffer cb, const char *caller_name) {
349711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
349811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                   (uint64_t)cb, __LINE__, DRAWSTATE_NO_BEGIN_COMMAND_BUFFER, "DS",
349911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                   "You must call vkBeginCommandBuffer() before this call to %s", caller_name);
350011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
350111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
350211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertbool validateCmdsInCmdBuffer(const layer_data *dev_data, const GLOBAL_CB_NODE *pCB, const CMD_TYPE cmd_type) {
350311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!pCB->activeRenderPass)
350411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return false;
350511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
350611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB->activeSubpassContents == VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS &&
350711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        (cmd_type != CMD_EXECUTECOMMANDS && cmd_type != CMD_NEXTSUBPASS && cmd_type != CMD_ENDRENDERPASS)) {
350811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
350911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
351011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             "Commands cannot be called in a subpass using secondary command buffers.");
351111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else if (pCB->activeSubpassContents == VK_SUBPASS_CONTENTS_INLINE && cmd_type == CMD_EXECUTECOMMANDS) {
351211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
351311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
351411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             "vkCmdExecuteCommands() cannot be called in a subpass using inline commands.");
351511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
351611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skip_call;
351711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
351811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
351911cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool checkGraphicsBit(const layer_data *my_data, VkQueueFlags flags, const char *name) {
352011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!(flags & VK_QUEUE_GRAPHICS_BIT))
352111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
352211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                       DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
352311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                       "Cannot call %s on a command buffer allocated from a pool without graphics capabilities.", name);
352411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return false;
352511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
352611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
352711cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool checkComputeBit(const layer_data *my_data, VkQueueFlags flags, const char *name) {
352811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!(flags & VK_QUEUE_COMPUTE_BIT))
352911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
353011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                       DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
353111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                       "Cannot call %s on a command buffer allocated from a pool without compute capabilities.", name);
353211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return false;
353311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
353411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
353511cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool checkGraphicsOrComputeBit(const layer_data *my_data, VkQueueFlags flags, const char *name) {
353611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!((flags & VK_QUEUE_GRAPHICS_BIT) || (flags & VK_QUEUE_COMPUTE_BIT)))
353711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
353811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                       DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
353911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                       "Cannot call %s on a command buffer allocated from a pool without graphics capabilities.", name);
354011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return false;
354111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
354211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
354311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Add specified CMD to the CmdBuffer in given pCB, flagging errors if CB is not
354411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//  in the recording state or if there's an issue with the Cmd ordering
354511cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool addCmd(const layer_data *my_data, GLOBAL_CB_NODE *pCB, const CMD_TYPE cmd, const char *caller_name) {
354611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
354711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto pool_data = my_data->commandPoolMap.find(pCB->createInfo.commandPool);
354811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pool_data != my_data->commandPoolMap.end()) {
354911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        VkQueueFlags flags = my_data->phys_dev_properties.queue_family_properties[pool_data->second.queueFamilyIndex].queueFlags;
355011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        switch (cmd) {
355111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_BINDPIPELINE:
355211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_BINDPIPELINEDELTA:
355311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_BINDDESCRIPTORSETS:
355411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_FILLBUFFER:
355511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_CLEARCOLORIMAGE:
355611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_SETEVENT:
355711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_RESETEVENT:
355811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_WAITEVENTS:
355911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_BEGINQUERY:
356011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_ENDQUERY:
356111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_RESETQUERYPOOL:
356211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_COPYQUERYPOOLRESULTS:
356311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_WRITETIMESTAMP:
356411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= checkGraphicsOrComputeBit(my_data, flags, cmdTypeToString(cmd).c_str());
356511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            break;
356611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_SETVIEWPORTSTATE:
356711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_SETSCISSORSTATE:
356811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_SETLINEWIDTHSTATE:
356911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_SETDEPTHBIASSTATE:
357011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_SETBLENDSTATE:
357111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_SETDEPTHBOUNDSSTATE:
357211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_SETSTENCILREADMASKSTATE:
357311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_SETSTENCILWRITEMASKSTATE:
357411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_SETSTENCILREFERENCESTATE:
357511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_BINDINDEXBUFFER:
357611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_BINDVERTEXBUFFER:
357711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_DRAW:
357811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_DRAWINDEXED:
357911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_DRAWINDIRECT:
358011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_DRAWINDEXEDINDIRECT:
358111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_BLITIMAGE:
358211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_CLEARATTACHMENTS:
358311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_CLEARDEPTHSTENCILIMAGE:
358411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_RESOLVEIMAGE:
358511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_BEGINRENDERPASS:
358611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_NEXTSUBPASS:
358711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_ENDRENDERPASS:
358811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= checkGraphicsBit(my_data, flags, cmdTypeToString(cmd).c_str());
358911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            break;
359011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_DISPATCH:
359111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_DISPATCHINDIRECT:
359211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= checkComputeBit(my_data, flags, cmdTypeToString(cmd).c_str());
359311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            break;
359411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_COPYBUFFER:
359511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_COPYIMAGE:
359611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_COPYBUFFERTOIMAGE:
359711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_COPYIMAGETOBUFFER:
359811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_CLONEIMAGEDATA:
359911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_UPDATEBUFFER:
360011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_PIPELINEBARRIER:
360111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_EXECUTECOMMANDS:
360211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case CMD_END:
360311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            break;
360411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        default:
360511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            break;
360611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
360711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
360811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB->state != CB_RECORDING) {
360911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= report_error_no_cb_begin(my_data, pCB->commandBuffer, caller_name);
361011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else {
361111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= validateCmdsInCmdBuffer(my_data, pCB, cmd);
361211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        CMD_NODE cmdNode = {};
361311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // init cmd node and append to end of cmd LL
361411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        cmdNode.cmdNumber = ++pCB->numCmds;
361511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        cmdNode.type = cmd;
361611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->cmds.push_back(cmdNode);
361711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
361811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skipCall;
361911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
362011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Reset the command buffer state
362111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//  Maintain the createInfo and set state to CB_NEW, but clear all other state
362211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void resetCB(layer_data *dev_data, const VkCommandBuffer cb) {
362311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = dev_data->commandBufferMap[cb];
362411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
362511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->in_use.store(0);
362611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->cmds.clear();
362711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Reset CB state (note that createInfo is not cleared)
362811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->commandBuffer = cb;
362911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        memset(&pCB->beginInfo, 0, sizeof(VkCommandBufferBeginInfo));
363011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        memset(&pCB->inheritanceInfo, 0, sizeof(VkCommandBufferInheritanceInfo));
363111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->numCmds = 0;
363211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        memset(pCB->drawCount, 0, NUM_DRAW_TYPES * sizeof(uint64_t));
363311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->state = CB_NEW;
363411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->submitCount = 0;
363511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->status = 0;
363611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->viewports.clear();
363711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->scissors.clear();
363811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
363911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t i = 0; i < VK_PIPELINE_BIND_POINT_RANGE_SIZE; ++i) {
364011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // Before clearing lastBoundState, remove any CB bindings from all uniqueBoundSets
364111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (auto set : pCB->lastBound[i].uniqueBoundSets) {
364211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                set->RemoveBoundCommandBuffer(pCB);
364311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
364411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pCB->lastBound[i].reset();
364511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
364611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
364711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        memset(&pCB->activeRenderPassBeginInfo, 0, sizeof(pCB->activeRenderPassBeginInfo));
364811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->activeRenderPass = nullptr;
364911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->activeSubpassContents = VK_SUBPASS_CONTENTS_INLINE;
365011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->activeSubpass = 0;
365111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->lastSubmittedFence = VK_NULL_HANDLE;
365211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->lastSubmittedQueue = VK_NULL_HANDLE;
365311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->destroyedSets.clear();
365411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->updatedSets.clear();
365511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->destroyedFramebuffers.clear();
365611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->waitedEvents.clear();
365711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->semaphores.clear();
365811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->events.clear();
365911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->waitedEventsBeforeQueryReset.clear();
366011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->queryToStateMap.clear();
366111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->activeQueries.clear();
366211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->startedQueries.clear();
366311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->imageSubresourceMap.clear();
366411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->imageLayoutMap.clear();
366511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->eventToStageMap.clear();
366611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->drawData.clear();
366711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->currentDrawData.buffers.clear();
366811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->primaryCommandBuffer = VK_NULL_HANDLE;
366911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Make sure any secondaryCommandBuffers are removed from globalInFlight
367011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (auto secondary_cb : pCB->secondaryCommandBuffers) {
367111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            dev_data->globalInFlightCmdBuffers.erase(secondary_cb);
367211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
367311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->secondaryCommandBuffers.clear();
367411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->updateImages.clear();
367511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->updateBuffers.clear();
367611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        clear_cmd_buf_and_mem_references(dev_data, pCB);
367711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->eventUpdates.clear();
367811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->queryUpdates.clear();
367911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
368011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Remove this cmdBuffer's reference from each FrameBuffer's CB ref list
368111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (auto framebuffer : pCB->framebuffers) {
368211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            auto fbNode = getFramebuffer(dev_data, framebuffer);
368311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (fbNode)
368411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                fbNode->referencingCmdBuffers.erase(pCB->commandBuffer);
368511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
368611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->framebuffers.clear();
368711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->activeFramebuffer = VK_NULL_HANDLE;
368811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
368911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
369011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
369111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Set PSO-related status bits for CB, including dynamic state set via PSO
369211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void set_cb_pso_status(GLOBAL_CB_NODE *pCB, const PIPELINE_NODE *pPipe) {
369311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Account for any dynamic state not set via this PSO
369411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!pPipe->graphicsPipelineCI.pDynamicState ||
369511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        !pPipe->graphicsPipelineCI.pDynamicState->dynamicStateCount) { // All state is static
369611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->status = CBSTATUS_ALL;
369711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else {
369811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // First consider all state on
369911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Then unset any state that's noted as dynamic in PSO
370011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Finally OR that into CB statemask
370111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        CBStatusFlags psoDynStateMask = CBSTATUS_ALL;
370211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t i = 0; i < pPipe->graphicsPipelineCI.pDynamicState->dynamicStateCount; i++) {
370311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            switch (pPipe->graphicsPipelineCI.pDynamicState->pDynamicStates[i]) {
370411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case VK_DYNAMIC_STATE_VIEWPORT:
370511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                psoDynStateMask &= ~CBSTATUS_VIEWPORT_SET;
370611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
370711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case VK_DYNAMIC_STATE_SCISSOR:
370811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                psoDynStateMask &= ~CBSTATUS_SCISSOR_SET;
370911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
371011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case VK_DYNAMIC_STATE_LINE_WIDTH:
371111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                psoDynStateMask &= ~CBSTATUS_LINE_WIDTH_SET;
371211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
371311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case VK_DYNAMIC_STATE_DEPTH_BIAS:
371411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                psoDynStateMask &= ~CBSTATUS_DEPTH_BIAS_SET;
371511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
371611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case VK_DYNAMIC_STATE_BLEND_CONSTANTS:
371711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                psoDynStateMask &= ~CBSTATUS_BLEND_CONSTANTS_SET;
371811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
371911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case VK_DYNAMIC_STATE_DEPTH_BOUNDS:
372011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                psoDynStateMask &= ~CBSTATUS_DEPTH_BOUNDS_SET;
372111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
372211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK:
372311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                psoDynStateMask &= ~CBSTATUS_STENCIL_READ_MASK_SET;
372411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
372511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case VK_DYNAMIC_STATE_STENCIL_WRITE_MASK:
372611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                psoDynStateMask &= ~CBSTATUS_STENCIL_WRITE_MASK_SET;
372711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
372811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            case VK_DYNAMIC_STATE_STENCIL_REFERENCE:
372911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                psoDynStateMask &= ~CBSTATUS_STENCIL_REFERENCE_SET;
373011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
373111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            default:
373211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                // TODO : Flag error here
373311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
373411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
373511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
373611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->status |= psoDynStateMask;
373711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
373811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
373911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
374011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Print the last bound Gfx Pipeline
374111cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool printPipeline(layer_data *my_data, const VkCommandBuffer cb) {
374211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
374311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(my_data, cb);
374411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
374511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        PIPELINE_NODE *pPipeTrav = getPipeline(my_data, pCB->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].pipeline);
374611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!pPipeTrav) {
374711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // nothing to print
374811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
374911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
375011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                __LINE__, DRAWSTATE_NONE, "DS", "%s",
375111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                vk_print_vkgraphicspipelinecreateinfo(
375211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    reinterpret_cast<const VkGraphicsPipelineCreateInfo *>(&pPipeTrav->graphicsPipelineCI), "{DS}")
375311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    .c_str());
375411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
375511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
375611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skipCall;
375711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
375811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
375911cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void printCB(layer_data *my_data, const VkCommandBuffer cb) {
376011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(my_data, cb);
376111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB && pCB->cmds.size() > 0) {
376211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
376311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                DRAWSTATE_NONE, "DS", "Cmds in CB 0x%p", (void *)cb);
376411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        vector<CMD_NODE> cmds = pCB->cmds;
376511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (auto ii = cmds.begin(); ii != cmds.end(); ++ii) {
376611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // TODO : Need to pass cb as srcObj here
376711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
376811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    __LINE__, DRAWSTATE_NONE, "DS", "  CMD 0x%" PRIx64 ": %s", (*ii).cmdNumber, cmdTypeToString((*ii).type).c_str());
376911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
377011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else {
377111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Nothing to print
377211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
377311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
377411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
377511cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool synchAndPrintDSConfig(layer_data *my_data, const VkCommandBuffer cb) {
377611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
377711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!(my_data->report_data->active_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT)) {
377811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return skipCall;
377911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
378011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= printPipeline(my_data, cb);
378111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skipCall;
378211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
378311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
378411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Flags validation error if the associated call is made inside a render pass. The apiName
378511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// routine should ONLY be called outside a render pass.
378611cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool insideRenderPass(const layer_data *my_data, GLOBAL_CB_NODE *pCB, const char *apiName) {
378711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool inside = false;
378811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB->activeRenderPass) {
378911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        inside = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
379011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                         (uint64_t)pCB->commandBuffer, __LINE__, DRAWSTATE_INVALID_RENDERPASS_CMD, "DS",
379111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                         "%s: It is invalid to issue this call inside an active render pass (0x%" PRIxLEAST64 ")", apiName,
379211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                         (uint64_t)pCB->activeRenderPass->renderPass);
379311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
379411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return inside;
379511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
379611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
379711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Flags validation error if the associated call is made outside a render pass. The apiName
379811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// routine should ONLY be called inside a render pass.
379911cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool outsideRenderPass(const layer_data *my_data, GLOBAL_CB_NODE *pCB, const char *apiName) {
380011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool outside = false;
380111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (((pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_PRIMARY) && (!pCB->activeRenderPass)) ||
380211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        ((pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY) && (!pCB->activeRenderPass) &&
380311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert         !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT))) {
380411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        outside = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
380511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                          (uint64_t)pCB->commandBuffer, __LINE__, DRAWSTATE_NO_ACTIVE_RENDERPASS, "DS",
380611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                          "%s: This call must be issued inside an active render pass.", apiName);
380711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
380811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return outside;
380911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
381011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
381111cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void init_core_validation(layer_data *instance_data, const VkAllocationCallbacks *pAllocator) {
381211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
381311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_debug_actions(instance_data->report_data, instance_data->logging_callback, pAllocator, "lunarg_core_validation");
381411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
381511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
381611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
381711cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL
381811cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkInstance *pInstance) {
381911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkLayerInstanceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
382011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
382111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    assert(chain_info->u.pLayerInfo);
382211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
382311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance");
382411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (fpCreateInstance == NULL)
382511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return VK_ERROR_INITIALIZATION_FAILED;
382611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
382711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Advance the link info for the next element on the chain
382811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
382911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
383011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
383111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (result != VK_SUCCESS)
383211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return result;
383311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
383411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *instance_data = get_my_data_ptr(get_dispatch_key(*pInstance), layer_data_map);
383511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    instance_data->instance = *pInstance;
383611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    instance_data->instance_dispatch_table = new VkLayerInstanceDispatchTable;
383711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_init_instance_dispatch_table(*pInstance, instance_data->instance_dispatch_table, fpGetInstanceProcAddr);
383811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
383911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    instance_data->report_data =
384011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        debug_report_create_instance(instance_data->instance_dispatch_table, *pInstance, pCreateInfo->enabledExtensionCount,
384111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                     pCreateInfo->ppEnabledExtensionNames);
384211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
384311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    init_core_validation(instance_data, pAllocator);
384411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
384511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    ValidateLayerOrdering(*pCreateInfo);
384611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
384711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
384811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
384911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
385011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert/* hook DestroyInstance to remove tableInstanceMap entry */
385111cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL DestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
385211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODOSC : Shouldn't need any customization here
385311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    dispatch_key key = get_dispatch_key(instance);
385411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TBD: Need any locking this early, in case this function is called at the
385511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // same time by more than one thread?
385611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *my_data = get_my_data_ptr(key, layer_data_map);
385711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table;
385811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    pTable->DestroyInstance(instance, pAllocator);
385911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
386011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::lock_guard<std::mutex> lock(global_lock);
386111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Clean up logging callback, if any
386211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    while (my_data->logging_callback.size() > 0) {
386311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        VkDebugReportCallbackEXT callback = my_data->logging_callback.back();
386411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        layer_destroy_msg_callback(my_data->report_data, callback, pAllocator);
386511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        my_data->logging_callback.pop_back();
386611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
386711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
386811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_debug_report_destroy_instance(my_data->report_data);
386911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    delete my_data->instance_dispatch_table;
387011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data_map.erase(key);
387111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
387211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
387311cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void createDeviceRegisterExtensions(const VkDeviceCreateInfo *pCreateInfo, VkDevice device) {
387411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    uint32_t i;
387511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TBD: Need any locking, in case this function is called at the same time
387611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // by more than one thread?
387711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
387811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    dev_data->device_extensions.wsi_enabled = false;
387911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
388011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkLayerDispatchTable *pDisp = dev_data->device_dispatch_table;
388111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    PFN_vkGetDeviceProcAddr gpa = pDisp->GetDeviceProcAddr;
388211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    pDisp->CreateSwapchainKHR = (PFN_vkCreateSwapchainKHR)gpa(device, "vkCreateSwapchainKHR");
388311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    pDisp->DestroySwapchainKHR = (PFN_vkDestroySwapchainKHR)gpa(device, "vkDestroySwapchainKHR");
388411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    pDisp->GetSwapchainImagesKHR = (PFN_vkGetSwapchainImagesKHR)gpa(device, "vkGetSwapchainImagesKHR");
388511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    pDisp->AcquireNextImageKHR = (PFN_vkAcquireNextImageKHR)gpa(device, "vkAcquireNextImageKHR");
388611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    pDisp->QueuePresentKHR = (PFN_vkQueuePresentKHR)gpa(device, "vkQueuePresentKHR");
388711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
388811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
388911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0)
389011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            dev_data->device_extensions.wsi_enabled = true;
389111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
389211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
389311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
389411cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL CreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo,
389511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
389611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *my_instance_data = get_my_data_ptr(get_dispatch_key(gpu), layer_data_map);
389711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkLayerDeviceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
389811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
389911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    assert(chain_info->u.pLayerInfo);
390011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
390111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;
390211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(my_instance_data->instance, "vkCreateDevice");
390311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (fpCreateDevice == NULL) {
390411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return VK_ERROR_INITIALIZATION_FAILED;
390511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
390611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
390711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Advance the link info for the next element on the chain
390811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
390911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
391011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = fpCreateDevice(gpu, pCreateInfo, pAllocator, pDevice);
391111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (result != VK_SUCCESS) {
391211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return result;
391311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
391411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
391511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
391611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *my_device_data = get_my_data_ptr(get_dispatch_key(*pDevice), layer_data_map);
391711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
391811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Setup device dispatch table
391911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    my_device_data->device_dispatch_table = new VkLayerDispatchTable;
392011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_init_device_dispatch_table(*pDevice, my_device_data->device_dispatch_table, fpGetDeviceProcAddr);
392111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    my_device_data->device = *pDevice;
392211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
392311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    my_device_data->report_data = layer_debug_report_create_device(my_instance_data->report_data, *pDevice);
392411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    createDeviceRegisterExtensions(pCreateInfo, *pDevice);
392511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Get physical device limits for this device
392611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    my_instance_data->instance_dispatch_table->GetPhysicalDeviceProperties(gpu, &(my_device_data->phys_dev_properties.properties));
392711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    uint32_t count;
392811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    my_instance_data->instance_dispatch_table->GetPhysicalDeviceQueueFamilyProperties(gpu, &count, nullptr);
392911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    my_device_data->phys_dev_properties.queue_family_properties.resize(count);
393011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    my_instance_data->instance_dispatch_table->GetPhysicalDeviceQueueFamilyProperties(
393111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        gpu, &count, &my_device_data->phys_dev_properties.queue_family_properties[0]);
393211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODO: device limits should make sure these are compatible
393311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCreateInfo->pEnabledFeatures) {
393411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        my_device_data->phys_dev_properties.features = *pCreateInfo->pEnabledFeatures;
393511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else {
393611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        memset(&my_device_data->phys_dev_properties.features, 0, sizeof(VkPhysicalDeviceFeatures));
393711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
393811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Store physical device mem limits into device layer_data struct
393911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    my_instance_data->instance_dispatch_table->GetPhysicalDeviceMemoryProperties(gpu, &my_device_data->phys_dev_mem_props);
394011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
394111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
394211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    ValidateLayerOrdering(*pCreateInfo);
394311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
394411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
394511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
394611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
394711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// prototype
394811cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void deleteRenderPasses(layer_data *);
394911cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL DestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) {
395011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODOSC : Shouldn't need any customization here
395111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    dispatch_key key = get_dispatch_key(device);
395211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(key, layer_data_map);
395311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Free all the memory
395411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
395511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    deletePipelines(dev_data);
395611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    deleteRenderPasses(dev_data);
395711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    deleteCommandBuffers(dev_data);
395811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // This will also delete all sets in the pool & remove them from setMap
395911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    deletePools(dev_data);
396011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // All sets should be removed
396111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    assert(dev_data->setMap.empty());
396211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto del_layout : dev_data->descriptorSetLayoutMap) {
396311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        delete del_layout.second;
396411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
396511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    dev_data->descriptorSetLayoutMap.clear();
396611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    dev_data->imageViewMap.clear();
396711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    dev_data->imageMap.clear();
396811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    dev_data->imageSubresourceMap.clear();
396911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    dev_data->imageLayoutMap.clear();
397011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    dev_data->bufferViewMap.clear();
397111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    dev_data->bufferMap.clear();
397211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Queues persist until device is destroyed
397311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    dev_data->queueMap.clear();
397411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
397511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#if MTMERGESOURCE
397611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
397711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.lock();
397811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
397911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            (uint64_t)device, __LINE__, MEMTRACK_NONE, "MEM", "Printing List details prior to vkDestroyDevice()");
398011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
398111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            (uint64_t)device, __LINE__, MEMTRACK_NONE, "MEM", "================================================");
398211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    print_mem_list(dev_data);
398311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    printCBList(dev_data);
398411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Report any memory leaks
398511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    DEVICE_MEM_INFO *pInfo = NULL;
398611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!dev_data->memObjMap.empty()) {
398711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (auto ii = dev_data->memObjMap.begin(); ii != dev_data->memObjMap.end(); ++ii) {
398811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pInfo = &(*ii).second;
398911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (pInfo->allocInfo.allocationSize != 0) {
399011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                // Valid Usage: All child objects created on device must have been destroyed prior to destroying device
399111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skipCall |=
399211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
399311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)pInfo->mem, __LINE__, MEMTRACK_MEMORY_LEAK,
399411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "MEM", "Mem Object 0x%" PRIx64 " has not been freed. You should clean up this memory by calling "
399511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                   "vkFreeMemory(0x%" PRIx64 ") prior to vkDestroyDevice().",
399611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            (uint64_t)(pInfo->mem), (uint64_t)(pInfo->mem));
399711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
399811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
399911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
400011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_debug_report_destroy_device(device);
400111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
400211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
400311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#if DISPATCH_MAP_DEBUG
400411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    fprintf(stderr, "Device: 0x%p, key: 0x%p\n", device, key);
400511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#endif
400611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkLayerDispatchTable *pDisp = dev_data->device_dispatch_table;
400711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall) {
400811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pDisp->DestroyDevice(device, pAllocator);
400911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
401011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#else
401111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    dev_data->device_dispatch_table->DestroyDevice(device, pAllocator);
401211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#endif
401311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    delete dev_data->device_dispatch_table;
401411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data_map.erase(key);
401511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
401611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
401711cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic const VkExtensionProperties instance_extensions[] = {{VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION}};
401811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
401911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// This validates that the initial layout specified in the command buffer for
402011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// the IMAGE is the same
402111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// as the global IMAGE layout
402211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool ValidateCmdBufImageLayouts(layer_data *dev_data, GLOBAL_CB_NODE *pCB) {
402311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
402411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto cb_image_data : pCB->imageLayoutMap) {
402511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        VkImageLayout imageLayout;
402611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!FindLayout(dev_data, cb_image_data.first, imageLayout)) {
402711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |=
402811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
402911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Cannot submit cmd buffer using deleted image 0x%" PRIx64 ".",
403011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        reinterpret_cast<const uint64_t &>(cb_image_data.first));
403111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
403211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (cb_image_data.second.initialLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
403311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                // TODO: Set memory invalid which is in mem_tracker currently
403411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            } else if (imageLayout != cb_image_data.second.initialLayout) {
403511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (cb_image_data.first.hasSubresource) {
403611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skip_call |= log_msg(
403711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
403811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        reinterpret_cast<uint64_t &>(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
403911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "Cannot submit cmd buffer using image (0x%" PRIx64 ") [sub-resource: aspectMask 0x%X array layer %u, mip level %u], "
404011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "with layout %s when first use is %s.",
404111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        reinterpret_cast<const uint64_t &>(cb_image_data.first.image), cb_image_data.first.subresource.aspectMask,
404211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                cb_image_data.first.subresource.arrayLayer,
404311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                cb_image_data.first.subresource.mipLevel, string_VkImageLayout(imageLayout),
404411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        string_VkImageLayout(cb_image_data.second.initialLayout));
404511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                } else {
404611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skip_call |= log_msg(
404711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
404811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        reinterpret_cast<uint64_t &>(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
404911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "Cannot submit cmd buffer using image (0x%" PRIx64 ") with layout %s when "
405011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "first use is %s.",
405111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        reinterpret_cast<const uint64_t &>(cb_image_data.first.image), string_VkImageLayout(imageLayout),
405211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        string_VkImageLayout(cb_image_data.second.initialLayout));
405311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
405411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
405511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            SetLayout(dev_data, cb_image_data.first, cb_image_data.second.layout);
405611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
405711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
405811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skip_call;
405911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
406011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
406111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Track which resources are in-flight by atomically incrementing their "in_use" count
406211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validateAndIncrementResources(layer_data *my_data, GLOBAL_CB_NODE *pCB) {
406311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
406411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto drawDataElement : pCB->drawData) {
406511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (auto buffer : drawDataElement.buffers) {
406611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            auto buffer_data = my_data->bufferMap.find(buffer);
406711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (buffer_data == my_data->bufferMap.end()) {
406811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
406911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                     (uint64_t)(buffer), __LINE__, DRAWSTATE_INVALID_BUFFER, "DS",
407011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                     "Cannot submit cmd buffer using deleted buffer 0x%" PRIx64 ".", (uint64_t)(buffer));
407111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            } else {
407211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                buffer_data->second.in_use.fetch_add(1);
407311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
407411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
407511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
407611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < VK_PIPELINE_BIND_POINT_RANGE_SIZE; ++i) {
407711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (auto set : pCB->lastBound[i].uniqueBoundSets) {
407811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (!my_data->setMap.count(set->GetSet())) {
407911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skip_call |=
408011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
408111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            (uint64_t)(set), __LINE__, DRAWSTATE_INVALID_DESCRIPTOR_SET, "DS",
408211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "Cannot submit cmd buffer using deleted descriptor set 0x%" PRIx64 ".", (uint64_t)(set));
408311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            } else {
408411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                set->in_use.fetch_add(1);
408511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
408611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
408711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
408811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto semaphore : pCB->semaphores) {
408911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto semaphoreNode = my_data->semaphoreMap.find(semaphore);
409011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (semaphoreNode == my_data->semaphoreMap.end()) {
409111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |=
409211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
409311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        reinterpret_cast<uint64_t &>(semaphore), __LINE__, DRAWSTATE_INVALID_SEMAPHORE, "DS",
409411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "Cannot submit cmd buffer using deleted semaphore 0x%" PRIx64 ".", reinterpret_cast<uint64_t &>(semaphore));
409511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
409611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            semaphoreNode->second.in_use.fetch_add(1);
409711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
409811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
409911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto event : pCB->events) {
410011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto eventNode = my_data->eventMap.find(event);
410111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (eventNode == my_data->eventMap.end()) {
410211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |=
410311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
410411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        reinterpret_cast<uint64_t &>(event), __LINE__, DRAWSTATE_INVALID_EVENT, "DS",
410511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "Cannot submit cmd buffer using deleted event 0x%" PRIx64 ".", reinterpret_cast<uint64_t &>(event));
410611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
410711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            eventNode->second.in_use.fetch_add(1);
410811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
410911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
411011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto event : pCB->writeEventsBeforeWait) {
411111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto eventNode = my_data->eventMap.find(event);
411211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        eventNode->second.write_in_use++;
411311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
411411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skip_call;
411511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
411611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
411711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Note: This function assumes that the global lock is held by the calling
411811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// thread.
411911cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool cleanInFlightCmdBuffer(layer_data *my_data, VkCommandBuffer cmdBuffer) {
412011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
412111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(my_data, cmdBuffer);
412211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
412311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (auto queryEventsPair : pCB->waitedEventsBeforeQueryReset) {
412411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (auto event : queryEventsPair.second) {
412511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (my_data->eventMap[event].needsSignaled) {
412611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
412711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, 0, DRAWSTATE_INVALID_QUERY, "DS",
412811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         "Cannot get query results on queryPool 0x%" PRIx64
412911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         " with index %d which was guarded by unsignaled event 0x%" PRIx64 ".",
413011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         (uint64_t)(queryEventsPair.first.pool), queryEventsPair.first.index, (uint64_t)(event));
413111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
413211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
413311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
413411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
413511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skip_call;
413611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
413711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Decrement cmd_buffer in_use and if it goes to 0 remove cmd_buffer from globalInFlightCmdBuffers
413811cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic inline void removeInFlightCmdBuffer(layer_data *dev_data, VkCommandBuffer cmd_buffer) {
413911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Pull it off of global list initially, but if we find it in any other queue list, add it back in
414011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmd_buffer);
414111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    pCB->in_use.fetch_sub(1);
414211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!pCB->in_use.load()) {
414311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->globalInFlightCmdBuffers.erase(cmd_buffer);
414411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
414511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
414611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
414711cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void decrementResources(layer_data *my_data, VkCommandBuffer cmdBuffer) {
414811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(my_data, cmdBuffer);
414911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto drawDataElement : pCB->drawData) {
415011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (auto buffer : drawDataElement.buffers) {
415111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            auto buffer_data = my_data->bufferMap.find(buffer);
415211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (buffer_data != my_data->bufferMap.end()) {
415311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                buffer_data->second.in_use.fetch_sub(1);
415411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
415511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
415611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
415711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < VK_PIPELINE_BIND_POINT_RANGE_SIZE; ++i) {
415811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (auto set : pCB->lastBound[i].uniqueBoundSets) {
415911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            set->in_use.fetch_sub(1);
416011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
416111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
416211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto semaphore : pCB->semaphores) {
416311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto semaphoreNode = my_data->semaphoreMap.find(semaphore);
416411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (semaphoreNode != my_data->semaphoreMap.end()) {
416511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            semaphoreNode->second.in_use.fetch_sub(1);
416611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
416711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
416811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto event : pCB->events) {
416911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto eventNode = my_data->eventMap.find(event);
417011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (eventNode != my_data->eventMap.end()) {
417111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            eventNode->second.in_use.fetch_sub(1);
417211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
417311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
417411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto event : pCB->writeEventsBeforeWait) {
417511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto eventNode = my_data->eventMap.find(event);
417611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (eventNode != my_data->eventMap.end()) {
417711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            eventNode->second.write_in_use--;
417811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
417911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
418011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto queryStatePair : pCB->queryToStateMap) {
418111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        my_data->queryToStateMap[queryStatePair.first] = queryStatePair.second;
418211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
418311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto eventStagePair : pCB->eventToStageMap) {
418411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        my_data->eventMap[eventStagePair.first].stageMask = eventStagePair.second;
418511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
418611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
418711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// For fenceCount fences in pFences, mark fence signaled, decrement in_use, and call
418811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//  decrementResources for all priorFences and cmdBuffers associated with fence.
418911cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool decrementResources(layer_data *my_data, uint32_t fenceCount, const VkFence *pFences) {
419011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
419111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::vector<std::pair<VkFence, FENCE_NODE *>> fence_pairs;
419211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < fenceCount; ++i) {
419311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto fence_data = my_data->fenceMap.find(pFences[i]);
419411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (fence_data == my_data->fenceMap.end() || !fence_data->second.needsSignaled)
419511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return skip_call;
419611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        fence_data->second.needsSignaled = false;
419711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (fence_data->second.in_use.load()) {
419811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            fence_pairs.push_back(std::make_pair(fence_data->first, &fence_data->second));
419911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            fence_data->second.in_use.fetch_sub(1);
420011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
420111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        decrementResources(my_data, static_cast<uint32_t>(fence_data->second.priorFences.size()),
420211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                           fence_data->second.priorFences.data());
420311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (auto cmdBuffer : fence_data->second.cmdBuffers) {
420411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            decrementResources(my_data, cmdBuffer);
420511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |= cleanInFlightCmdBuffer(my_data, cmdBuffer);
420611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            removeInFlightCmdBuffer(my_data, cmdBuffer);
420711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
420811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        fence_data->second.cmdBuffers.clear();
420911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        fence_data->second.priorFences.clear();
421011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
421111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto fence_pair : fence_pairs) {
421211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (auto queue : fence_pair.second->queues) {
421311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            auto queue_pair = my_data->queueMap.find(queue);
421411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (queue_pair != my_data->queueMap.end()) {
421511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                auto last_fence_data =
421611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    std::find(queue_pair->second.lastFences.begin(), queue_pair->second.lastFences.end(), fence_pair.first);
421711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (last_fence_data != queue_pair->second.lastFences.end())
421811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    queue_pair->second.lastFences.erase(last_fence_data);
421911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
422011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
422111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (auto& fence_data : my_data->fenceMap) {
422211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert          auto prior_fence_data =
422311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert              std::find(fence_data.second.priorFences.begin(), fence_data.second.priorFences.end(), fence_pair.first);
422411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert          if (prior_fence_data != fence_data.second.priorFences.end())
422511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert              fence_data.second.priorFences.erase(prior_fence_data);
422611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
422711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
422811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skip_call;
422911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
423011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Decrement in_use for all outstanding cmd buffers that were submitted on this queue
423111cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool decrementResources(layer_data *my_data, VkQueue queue) {
423211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
423311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto queue_data = my_data->queueMap.find(queue);
423411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (queue_data != my_data->queueMap.end()) {
423511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (auto cmdBuffer : queue_data->second.untrackedCmdBuffers) {
423611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            decrementResources(my_data, cmdBuffer);
423711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |= cleanInFlightCmdBuffer(my_data, cmdBuffer);
423811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            removeInFlightCmdBuffer(my_data, cmdBuffer);
423911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
424011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        queue_data->second.untrackedCmdBuffers.clear();
424111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= decrementResources(my_data, static_cast<uint32_t>(queue_data->second.lastFences.size()),
424211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        queue_data->second.lastFences.data());
424311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
424411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skip_call;
424511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
424611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
424711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// This function merges command buffer tracking between queues when there is a semaphore dependency
424811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// between them (see below for details as to how tracking works). When this happens, the prior
424911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// fences from the signaling queue are merged into the wait queue as well as any untracked command
425011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// buffers.
425111cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void updateTrackedCommandBuffers(layer_data *dev_data, VkQueue queue, VkQueue other_queue, VkFence fence) {
425211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (queue == other_queue) {
425311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return;
425411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
425511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto queue_data = dev_data->queueMap.find(queue);
425611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto other_queue_data = dev_data->queueMap.find(other_queue);
425711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (queue_data == dev_data->queueMap.end() || other_queue_data == dev_data->queueMap.end()) {
425811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return;
425911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
426011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto fenceInner : other_queue_data->second.lastFences) {
426111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        queue_data->second.lastFences.push_back(fenceInner);
426211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto fence_node = dev_data->fenceMap.find(fenceInner);
426311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (fence_node != dev_data->fenceMap.end()) {
426411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            fence_node->second.queues.insert(other_queue_data->first);
426511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
426611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
426711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (fence != VK_NULL_HANDLE) {
426811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto fence_data = dev_data->fenceMap.find(fence);
426911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (fence_data == dev_data->fenceMap.end()) {
427011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return;
427111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
427211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (auto cmdbuffer : other_queue_data->second.untrackedCmdBuffers) {
427311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            fence_data->second.cmdBuffers.push_back(cmdbuffer);
427411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
427511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        other_queue_data->second.untrackedCmdBuffers.clear();
427611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else {
427711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (auto cmdbuffer : other_queue_data->second.untrackedCmdBuffers) {
427811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            queue_data->second.untrackedCmdBuffers.push_back(cmdbuffer);
427911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
428011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        other_queue_data->second.untrackedCmdBuffers.clear();
428111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
428211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto eventStagePair : other_queue_data->second.eventToStageMap) {
428311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        queue_data->second.eventToStageMap[eventStagePair.first] = eventStagePair.second;
428411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
428511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto queryStatePair : other_queue_data->second.queryToStateMap) {
428611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        queue_data->second.queryToStateMap[queryStatePair.first] = queryStatePair.second;
428711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
428811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
428911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
429011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// This is the core function for tracking command buffers. There are two primary ways command
429111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// buffers are tracked. When submitted they are stored in the command buffer list associated
429211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// with a fence or the untracked command buffer list associated with a queue if no fence is used.
429311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Each queue also stores the last fence that was submitted onto the queue. This allows us to
429411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// create a linked list of fences and their associated command buffers so if one fence is
429511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// waited on, prior fences on that queue are also considered to have been waited on. When a fence is
429611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// waited on (either via a queue, device or fence), we free the cmd buffers for that fence and
429711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// recursively call with the prior fences.
429811cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void trackCommandBuffers(layer_data *my_data, VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits,
429911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                VkFence fence) {
430011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto queue_data = my_data->queueMap.find(queue);
430111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (fence != VK_NULL_HANDLE) {
430211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        vector<VkFence> prior_fences;
430311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto fence_data = my_data->fenceMap.find(fence);
430411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (fence_data == my_data->fenceMap.end()) {
430511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return;
430611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
430711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        fence_data->second.cmdBuffers.clear();
430811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (queue_data != my_data->queueMap.end()) {
430911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            prior_fences = queue_data->second.lastFences;
431011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            queue_data->second.lastFences.clear();
431111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            queue_data->second.lastFences.push_back(fence);
431211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (auto cmdbuffer : queue_data->second.untrackedCmdBuffers) {
431311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                fence_data->second.cmdBuffers.push_back(cmdbuffer);
431411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
431511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            queue_data->second.untrackedCmdBuffers.clear();
431611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
431711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        fence_data->second.priorFences = prior_fences;
431811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        fence_data->second.needsSignaled = true;
431911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        fence_data->second.queues.insert(queue);
432011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        fence_data->second.in_use.fetch_add(1);
432111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
432211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            const VkSubmitInfo *submit = &pSubmits[submit_idx];
432311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (uint32_t i = 0; i < submit->commandBufferCount; ++i) {
432411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                for (auto secondaryCmdBuffer : my_data->commandBufferMap[submit->pCommandBuffers[i]]->secondaryCommandBuffers) {
432511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    fence_data->second.cmdBuffers.push_back(secondaryCmdBuffer);
432611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
432711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                fence_data->second.cmdBuffers.push_back(submit->pCommandBuffers[i]);
432811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
432911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
433011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else {
433111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (queue_data != my_data->queueMap.end()) {
433211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
433311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                const VkSubmitInfo *submit = &pSubmits[submit_idx];
433411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                for (uint32_t i = 0; i < submit->commandBufferCount; ++i) {
433511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    for (auto secondaryCmdBuffer : my_data->commandBufferMap[submit->pCommandBuffers[i]]->secondaryCommandBuffers) {
433611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        queue_data->second.untrackedCmdBuffers.push_back(secondaryCmdBuffer);
433711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    }
433811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    queue_data->second.untrackedCmdBuffers.push_back(submit->pCommandBuffers[i]);
433911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
434011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
434111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
434211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
434311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
434411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
434511cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void markCommandBuffersInFlight(layer_data *my_data, VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits,
434611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                       VkFence fence) {
434711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto queue_data = my_data->queueMap.find(queue);
434811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (queue_data != my_data->queueMap.end()) {
434911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
435011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            const VkSubmitInfo *submit = &pSubmits[submit_idx];
435111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (uint32_t i = 0; i < submit->commandBufferCount; ++i) {
435211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                // Add cmdBuffers to the global set and increment count
435311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                GLOBAL_CB_NODE *pCB = getCBNode(my_data, submit->pCommandBuffers[i]);
435411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                for (auto secondaryCmdBuffer : my_data->commandBufferMap[submit->pCommandBuffers[i]]->secondaryCommandBuffers) {
435511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    my_data->globalInFlightCmdBuffers.insert(secondaryCmdBuffer);
435611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    GLOBAL_CB_NODE *pSubCB = getCBNode(my_data, secondaryCmdBuffer);
435711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    pSubCB->in_use.fetch_add(1);
435811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
435911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                my_data->globalInFlightCmdBuffers.insert(submit->pCommandBuffers[i]);
436011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pCB->in_use.fetch_add(1);
436111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
436211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
436311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
436411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
436511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
436611cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validateCommandBufferSimultaneousUse(layer_data *dev_data, GLOBAL_CB_NODE *pCB) {
436711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
436811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (dev_data->globalInFlightCmdBuffers.count(pCB->commandBuffer) &&
436911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
437011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |=
437111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
437211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    __LINE__, DRAWSTATE_INVALID_CB_SIMULTANEOUS_USE, "DS",
437311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    "Command Buffer 0x%" PRIx64 " is already in use and is not marked for simultaneous use.",
437411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    reinterpret_cast<uint64_t>(pCB->commandBuffer));
437511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
437611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skip_call;
437711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
437811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
437911cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validateCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB) {
438011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
438111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Validate ONE_TIME_SUBMIT_BIT CB is not being submitted more than once
438211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if ((pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) && (pCB->submitCount > 1)) {
438311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
438411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            __LINE__, DRAWSTATE_COMMAND_BUFFER_SINGLE_SUBMIT_VIOLATION, "DS",
438511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "CB 0x%" PRIxLEAST64 " was begun w/ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT "
438611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "set, but has been submitted 0x%" PRIxLEAST64 " times.",
438711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            (uint64_t)(pCB->commandBuffer), pCB->submitCount);
438811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
438911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Validate that cmd buffers have been updated
439011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (CB_RECORDED != pCB->state) {
439111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (CB_INVALID == pCB->state) {
439211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // Inform app of reason CB invalid
439311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            bool causeReported = false;
439411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (!pCB->destroyedSets.empty()) {
439511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                std::stringstream set_string;
439611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                for (auto set : pCB->destroyedSets)
439711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    set_string << " " << set;
439811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
439911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skipCall |=
440011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
440111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            (uint64_t)(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
440211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "You are submitting command buffer 0x%" PRIxLEAST64
440311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            " that is invalid because it had the following bound descriptor set(s) destroyed: %s",
440411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            (uint64_t)(pCB->commandBuffer), set_string.str().c_str());
440511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                causeReported = true;
440611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
440711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (!pCB->updatedSets.empty()) {
440811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                std::stringstream set_string;
440911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                for (auto set : pCB->updatedSets)
441011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    set_string << " " << set;
441111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
441211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skipCall |=
441311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
441411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            (uint64_t)(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
441511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "You are submitting command buffer 0x%" PRIxLEAST64
441611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            " that is invalid because it had the following bound descriptor set(s) updated: %s",
441711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            (uint64_t)(pCB->commandBuffer), set_string.str().c_str());
441811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                causeReported = true;
441911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
442011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (!pCB->destroyedFramebuffers.empty()) {
442111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                std::stringstream fb_string;
442211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                for (auto fb : pCB->destroyedFramebuffers)
442311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    fb_string << " " << fb;
442411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
442511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skipCall |=
442611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
442711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            reinterpret_cast<uint64_t &>(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
442811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "You are submitting command buffer 0x%" PRIxLEAST64 " that is invalid because it had the following "
442911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "referenced framebuffers destroyed: %s",
443011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            reinterpret_cast<uint64_t &>(pCB->commandBuffer), fb_string.str().c_str());
443111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                causeReported = true;
443211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
443311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // TODO : This is defensive programming to make sure an error is
443411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            //  flagged if we hit this INVALID cmd buffer case and none of the
443511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            //  above cases are hit. As the number of INVALID cases grows, this
443611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            //  code should be updated to seemlessly handle all the cases.
443711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (!causeReported) {
443811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skipCall |= log_msg(
443911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
444011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    reinterpret_cast<uint64_t &>(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
444111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    "You are submitting command buffer 0x%" PRIxLEAST64 " that is invalid due to an unknown cause. Validation "
444211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    "should "
444311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    "be improved to report the exact cause.",
444411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    reinterpret_cast<uint64_t &>(pCB->commandBuffer));
444511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
444611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else { // Flag error for using CB w/o vkEndCommandBuffer() called
444711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |=
444811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
444911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        (uint64_t)(pCB->commandBuffer), __LINE__, DRAWSTATE_NO_END_COMMAND_BUFFER, "DS",
445011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "You must call vkEndCommandBuffer() on CB 0x%" PRIxLEAST64 " before this call to vkQueueSubmit()!",
445111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        (uint64_t)(pCB->commandBuffer));
445211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
445311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
445411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skipCall;
445511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
445611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
445711cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validatePrimaryCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB) {
445811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Track in-use for resources off of primary and any secondary CBs
445911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = validateAndIncrementResources(dev_data, pCB);
446011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!pCB->secondaryCommandBuffers.empty()) {
446111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (auto secondaryCmdBuffer : pCB->secondaryCommandBuffers) {
446211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= validateAndIncrementResources(dev_data, dev_data->commandBufferMap[secondaryCmdBuffer]);
446311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            GLOBAL_CB_NODE *pSubCB = getCBNode(dev_data, secondaryCmdBuffer);
446411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if ((pSubCB->primaryCommandBuffer != pCB->commandBuffer) &&
446511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                !(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
446611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
446711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        __LINE__, DRAWSTATE_COMMAND_BUFFER_SINGLE_SUBMIT_VIOLATION, "DS",
446811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "CB 0x%" PRIxLEAST64 " was submitted with secondary buffer 0x%" PRIxLEAST64
446911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        " but that buffer has subsequently been bound to "
447011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "primary cmd buffer 0x%" PRIxLEAST64
447111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        " and it does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set.",
447211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        reinterpret_cast<uint64_t>(pCB->commandBuffer), reinterpret_cast<uint64_t>(secondaryCmdBuffer),
447311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        reinterpret_cast<uint64_t>(pSubCB->primaryCommandBuffer));
447411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
447511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
447611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
447711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= validateCommandBufferState(dev_data, pCB);
447811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // If USAGE_SIMULTANEOUS_USE_BIT not set then CB cannot already be executing
447911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // on device
448011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= validateCommandBufferSimultaneousUse(dev_data, pCB);
448111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skipCall;
448211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
448311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
448411cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL
448511cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertQueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence) {
448611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
448711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map);
448811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
448911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
449011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // First verify that fence is not in use
449111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (fence != VK_NULL_HANDLE) {
449211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if ((submitCount != 0) && dev_data->fenceMap[fence].in_use.load()) {
449311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
449411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                (uint64_t)(fence), __LINE__, DRAWSTATE_INVALID_FENCE, "DS",
449511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                "Fence 0x%" PRIx64 " is already in use by another submission.", (uint64_t)(fence));
449611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
449711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!dev_data->fenceMap[fence].needsSignaled) {
449811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
449911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                reinterpret_cast<uint64_t &>(fence), __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM",
450011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                "Fence 0x%" PRIxLEAST64 " submitted in SIGNALED state.  Fences must be reset before being submitted",
450111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                reinterpret_cast<uint64_t &>(fence));
450211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
450311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
450411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODO : Review these old print functions and clean up as appropriate
450511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    print_mem_list(dev_data);
450611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    printCBList(dev_data);
450711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Update cmdBuffer-related data structs and mark fence in-use
450811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    trackCommandBuffers(dev_data, queue, submitCount, pSubmits, fence);
450911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Now verify each individual submit
451011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unordered_set<VkQueue> processed_other_queues;
451111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
451211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        const VkSubmitInfo *submit = &pSubmits[submit_idx];
451311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        vector<VkSemaphore> semaphoreList;
451411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t i = 0; i < submit->waitSemaphoreCount; ++i) {
451511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            const VkSemaphore &semaphore = submit->pWaitSemaphores[i];
451611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            semaphoreList.push_back(semaphore);
451711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (dev_data->semaphoreMap.find(semaphore) != dev_data->semaphoreMap.end()) {
451811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (dev_data->semaphoreMap[semaphore].signaled) {
451911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    dev_data->semaphoreMap[semaphore].signaled = false;
452011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                } else {
452111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skipCall |=
452211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
452311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                reinterpret_cast<const uint64_t &>(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
452411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                "Queue 0x%" PRIx64 " is waiting on semaphore 0x%" PRIx64 " that has no way to be signaled.",
452511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                reinterpret_cast<uint64_t &>(queue), reinterpret_cast<const uint64_t &>(semaphore));
452611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
452711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                const VkQueue &other_queue = dev_data->semaphoreMap[semaphore].queue;
452811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (other_queue != VK_NULL_HANDLE && !processed_other_queues.count(other_queue)) {
452911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    updateTrackedCommandBuffers(dev_data, queue, other_queue, fence);
453011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    processed_other_queues.insert(other_queue);
453111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
453211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
453311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
453411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t i = 0; i < submit->signalSemaphoreCount; ++i) {
453511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            const VkSemaphore &semaphore = submit->pSignalSemaphores[i];
453611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (dev_data->semaphoreMap.find(semaphore) != dev_data->semaphoreMap.end()) {
453711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                semaphoreList.push_back(semaphore);
453811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (dev_data->semaphoreMap[semaphore].signaled) {
453911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skipCall |=
454011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
454111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                reinterpret_cast<const uint64_t &>(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
454211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                "Queue 0x%" PRIx64 " is signaling semaphore 0x%" PRIx64
454311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                " that has already been signaled but not waited on by queue 0x%" PRIx64 ".",
454411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                reinterpret_cast<uint64_t &>(queue), reinterpret_cast<const uint64_t &>(semaphore),
454511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                reinterpret_cast<uint64_t &>(dev_data->semaphoreMap[semaphore].queue));
454611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                } else {
454711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    dev_data->semaphoreMap[semaphore].signaled = true;
454811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    dev_data->semaphoreMap[semaphore].queue = queue;
454911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
455011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
455111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
455211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t i = 0; i < submit->commandBufferCount; i++) {
455311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            auto pCBNode = getCBNode(dev_data, submit->pCommandBuffers[i]);
455411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= ValidateCmdBufImageLayouts(dev_data, pCBNode);
455511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (pCBNode) {
455611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pCBNode->semaphores = semaphoreList;
455711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pCBNode->submitCount++; // increment submit count
455811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pCBNode->lastSubmittedFence = fence;
455911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pCBNode->lastSubmittedQueue = queue;
456011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skipCall |= validatePrimaryCommandBufferState(dev_data, pCBNode);
456111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                // Call submit-time functions to validate/update state
456211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                for (auto &function : pCBNode->validate_functions) {
456311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skipCall |= function();
456411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
456511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                for (auto &function : pCBNode->eventUpdates) {
456611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skipCall |= function(queue);
456711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
456811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                for (auto &function : pCBNode->queryUpdates) {
456911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skipCall |= function(queue);
457011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
457111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
457211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
457311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
457411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    markCommandBuffersInFlight(dev_data, queue, submitCount, pSubmits, fence);
457511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
457611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
457711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        result = dev_data->device_dispatch_table->QueueSubmit(queue, submitCount, pSubmits, fence);
457811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
457911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
458011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
458111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
458211cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL AllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo,
458311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                              const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory) {
458411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
458511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = my_data->device_dispatch_table->AllocateMemory(device, pAllocateInfo, pAllocator, pMemory);
458611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODO : Track allocations and overall size here
458711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::lock_guard<std::mutex> lock(global_lock);
458811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    add_mem_obj_info(my_data, device, *pMemory, pAllocateInfo);
458911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    print_mem_list(my_data);
459011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
459111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
459211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
459311cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
459411cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertFreeMemory(VkDevice device, VkDeviceMemory mem, const VkAllocationCallbacks *pAllocator) {
459511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
459611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
459711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // From spec : A memory object is freed by calling vkFreeMemory() when it is no longer needed.
459811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Before freeing a memory object, an application must ensure the memory object is no longer
459911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // in use by the device—for example by command buffers queued for execution. The memory need
460011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // not yet be unbound from all images and buffers, but any further use of those images or
460111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // buffers (on host or device) for anything other than destroying those objects will result in
460211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // undefined behavior.
460311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
460411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
460511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    freeMemObjInfo(my_data, device, mem, false);
460611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    print_mem_list(my_data);
460711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    printCBList(my_data);
460811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
460911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    my_data->device_dispatch_table->FreeMemory(device, mem, pAllocator);
461011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
461111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
461211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validateMemRange(layer_data *my_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size) {
461311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
461411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
461511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (size == 0) {
461611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
461711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                           (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, "MEM",
461811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                           "VkMapMemory: Attempting to map memory range of size zero");
461911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
462011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
462111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto mem_element = my_data->memObjMap.find(mem);
462211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (mem_element != my_data->memObjMap.end()) {
462311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // It is an application error to call VkMapMemory on an object that is already mapped
462411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (mem_element->second.memRange.size != 0) {
462511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
462611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                               (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, "MEM",
462711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                               "VkMapMemory: Attempting to map memory on an already-mapped object 0x%" PRIxLEAST64, (uint64_t)mem);
462811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
462911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
463011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Validate that offset + size is within object's allocationSize
463111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (size == VK_WHOLE_SIZE) {
463211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (offset >= mem_element->second.allocInfo.allocationSize) {
463311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
463411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                   VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP,
463511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                   "MEM", "Mapping Memory from 0x%" PRIx64 " to 0x%" PRIx64 " with size of VK_WHOLE_SIZE oversteps total array size 0x%" PRIx64, offset,
463611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                   mem_element->second.allocInfo.allocationSize, mem_element->second.allocInfo.allocationSize);
463711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
463811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
463911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if ((offset + size) > mem_element->second.allocInfo.allocationSize) {
464011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
464111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                   VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP,
464211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                   "MEM", "Mapping Memory from 0x%" PRIx64 " to 0x%" PRIx64 " oversteps total array size 0x%" PRIx64, offset,
464311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                   size + offset, mem_element->second.allocInfo.allocationSize);
464411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
464511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
464611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
464711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skipCall;
464811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
464911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
465011cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void storeMemRanges(layer_data *my_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size) {
465111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto mem_element = my_data->memObjMap.find(mem);
465211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (mem_element != my_data->memObjMap.end()) {
465311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        MemRange new_range;
465411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        new_range.offset = offset;
465511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        new_range.size = size;
465611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        mem_element->second.memRange = new_range;
465711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
465811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
465911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
466011cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool deleteMemRanges(layer_data *my_data, VkDeviceMemory mem) {
466111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
466211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto mem_element = my_data->memObjMap.find(mem);
466311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (mem_element != my_data->memObjMap.end()) {
466411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!mem_element->second.memRange.size) {
466511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // Valid Usage: memory must currently be mapped
466611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
466711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                               (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, "MEM",
466811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                               "Unmapping Memory without memory being mapped: mem obj 0x%" PRIxLEAST64, (uint64_t)mem);
466911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
467011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        mem_element->second.memRange.size = 0;
467111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (mem_element->second.pData) {
467211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            free(mem_element->second.pData);
467311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            mem_element->second.pData = 0;
467411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
467511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
467611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skipCall;
467711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
467811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
467911cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic char NoncoherentMemoryFillValue = 0xb;
468011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
468111cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void initializeAndTrackMemory(layer_data *dev_data, VkDeviceMemory mem, VkDeviceSize size, void **ppData) {
468211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto mem_element = dev_data->memObjMap.find(mem);
468311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (mem_element != dev_data->memObjMap.end()) {
468411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        mem_element->second.pDriverData = *ppData;
468511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        uint32_t index = mem_element->second.allocInfo.memoryTypeIndex;
468611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (dev_data->phys_dev_mem_props.memoryTypes[index].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) {
468711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            mem_element->second.pData = 0;
468811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
468911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (size == VK_WHOLE_SIZE) {
469011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                size = mem_element->second.allocInfo.allocationSize;
469111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
469211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            size_t convSize = (size_t)(size);
469311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            mem_element->second.pData = malloc(2 * convSize);
469411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            memset(mem_element->second.pData, NoncoherentMemoryFillValue, 2 * convSize);
469511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            *ppData = static_cast<char *>(mem_element->second.pData) + (convSize / 2);
469611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
469711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
469811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
469911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Verify that state for fence being waited on is appropriate. That is,
470011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//  a fence being waited on should not already be signalled and
470111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//  it should have been submitted on a queue or during acquire next image
470211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic inline bool verifyWaitFenceState(VkDevice device, VkFence fence, const char *apiCall) {
470311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
470411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
470511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto pFenceInfo = my_data->fenceMap.find(fence);
470611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pFenceInfo != my_data->fenceMap.end()) {
470711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!pFenceInfo->second.firstTimeFlag) {
470811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (!pFenceInfo->second.needsSignaled) {
470911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skipCall |=
471011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
471111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            (uint64_t)fence, __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM",
471211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "%s specified fence 0x%" PRIxLEAST64 " already in SIGNALED state.", apiCall, (uint64_t)fence);
471311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
471411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (pFenceInfo->second.queues.empty() && !pFenceInfo->second.swapchain) { // Checking status of unsubmitted fence
471511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
471611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    reinterpret_cast<uint64_t &>(fence), __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM",
471711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    "%s called for fence 0x%" PRIxLEAST64 " which has not been submitted on a Queue or during "
471811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    "acquire next image.",
471911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    apiCall, reinterpret_cast<uint64_t &>(fence));
472011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
472111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
472211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pFenceInfo->second.firstTimeFlag = false;
472311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
472411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
472511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skipCall;
472611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
472711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
472811cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL
472911cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertWaitForFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences, VkBool32 waitAll, uint64_t timeout) {
473011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
473111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
473211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Verify fence status of submitted fences
473311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
473411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < fenceCount; i++) {
473511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= verifyWaitFenceState(device, pFences[i], "vkWaitForFences");
473611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
473711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
473811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (skip_call)
473911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return VK_ERROR_VALIDATION_FAILED_EXT;
474011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
474111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = dev_data->device_dispatch_table->WaitForFences(device, fenceCount, pFences, waitAll, timeout);
474211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
474311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (result == VK_SUCCESS) {
474411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        lock.lock();
474511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // When we know that all fences are complete we can clean/remove their CBs
474611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (waitAll || fenceCount == 1) {
474711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |= decrementResources(dev_data, fenceCount, pFences);
474811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
474911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // NOTE : Alternate case not handled here is when some fences have completed. In
475011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        //  this case for app to guarantee which fences completed it will have to call
475111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        //  vkGetFenceStatus() at which point we'll clean/remove their CBs if complete.
475211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        lock.unlock();
475311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
475411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (skip_call)
475511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return VK_ERROR_VALIDATION_FAILED_EXT;
475611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
475711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
475811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
475911cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL GetFenceStatus(VkDevice device, VkFence fence) {
476011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
476111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
476211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
476311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
476411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall = verifyWaitFenceState(device, fence, "vkGetFenceStatus");
476511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
476611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
476711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (skipCall)
476811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return result;
476911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
477011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    result = dev_data->device_dispatch_table->GetFenceStatus(device, fence);
477111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
477211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.lock();
477311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (result == VK_SUCCESS) {
477411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= decrementResources(dev_data, 1, &fence);
477511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
477611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
477711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (skip_call)
477811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return VK_ERROR_VALIDATION_FAILED_EXT;
477911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
478011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
478111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
478211cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL GetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex,
478311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                            VkQueue *pQueue) {
478411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
478511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    dev_data->device_dispatch_table->GetDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue);
478611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::lock_guard<std::mutex> lock(global_lock);
478711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
478811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Add queue to tracking set only if it is new
478911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto result = dev_data->queues.emplace(*pQueue);
479011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (result.second == true) {
479111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        QUEUE_NODE *pQNode = &dev_data->queueMap[*pQueue];
479211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pQNode->device = device;
479311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
479411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
479511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
479611cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL QueueWaitIdle(VkQueue queue) {
479711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map);
479811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
479911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skip_call |= decrementResources(dev_data, queue);
480011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (skip_call)
480111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return VK_ERROR_VALIDATION_FAILED_EXT;
480211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = dev_data->device_dispatch_table->QueueWaitIdle(queue);
480311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
480411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
480511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
480611cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL DeviceWaitIdle(VkDevice device) {
480711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
480811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
480911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
481011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto queue : dev_data->queues) {
481111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= decrementResources(dev_data, queue);
481211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
481311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    dev_data->globalInFlightCmdBuffers.clear();
481411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
481511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (skip_call)
481611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return VK_ERROR_VALIDATION_FAILED_EXT;
481711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = dev_data->device_dispatch_table->DeviceWaitIdle(device);
481811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
481911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
482011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
482111cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL DestroyFence(VkDevice device, VkFence fence, const VkAllocationCallbacks *pAllocator) {
482211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
482311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
482411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
482511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto fence_pair = dev_data->fenceMap.find(fence);
482611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (fence_pair != dev_data->fenceMap.end()) {
482711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (fence_pair->second.in_use.load()) {
482811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
482911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                (uint64_t)(fence), __LINE__, DRAWSTATE_INVALID_FENCE, "DS",
483011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                "Fence 0x%" PRIx64 " is in use by a command buffer.", (uint64_t)(fence));
483111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
483211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->fenceMap.erase(fence_pair);
483311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
483411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
483511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
483611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
483711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->DestroyFence(device, fence, pAllocator);
483811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
483911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
484011cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
484111cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertDestroySemaphore(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks *pAllocator) {
484211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
484311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    dev_data->device_dispatch_table->DestroySemaphore(device, semaphore, pAllocator);
484411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::lock_guard<std::mutex> lock(global_lock);
484511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto item = dev_data->semaphoreMap.find(semaphore);
484611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (item != dev_data->semaphoreMap.end()) {
484711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (item->second.in_use.load()) {
484811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
484911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    reinterpret_cast<uint64_t &>(semaphore), __LINE__, DRAWSTATE_INVALID_SEMAPHORE, "DS",
485011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    "Cannot delete semaphore 0x%" PRIx64 " which is in use.", reinterpret_cast<uint64_t &>(semaphore));
485111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
485211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->semaphoreMap.erase(semaphore);
485311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
485411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODO : Clean up any internal data structures using this obj.
485511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
485611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
485711cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL DestroyEvent(VkDevice device, VkEvent event, const VkAllocationCallbacks *pAllocator) {
485811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
485911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
486011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
486111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto event_data = dev_data->eventMap.find(event);
486211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (event_data != dev_data->eventMap.end()) {
486311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (event_data->second.in_use.load()) {
486411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |= log_msg(
486511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
486611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                reinterpret_cast<uint64_t &>(event), __LINE__, DRAWSTATE_INVALID_EVENT, "DS",
486711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                "Cannot delete event 0x%" PRIx64 " which is in use by a command buffer.", reinterpret_cast<uint64_t &>(event));
486811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
486911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->eventMap.erase(event_data);
487011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
487111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
487211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skip_call)
487311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->DestroyEvent(device, event, pAllocator);
487411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODO : Clean up any internal data structures using this obj.
487511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
487611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
487711cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
487811cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertDestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks *pAllocator) {
487911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    get_my_data_ptr(get_dispatch_key(device), layer_data_map)
488011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        ->device_dispatch_table->DestroyQueryPool(device, queryPool, pAllocator);
488111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODO : Clean up any internal data structures using this obj.
488211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
488311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
488411cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL GetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery,
488511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                   uint32_t queryCount, size_t dataSize, void *pData, VkDeviceSize stride,
488611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                   VkQueryResultFlags flags) {
488711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
488811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    unordered_map<QueryObject, vector<VkCommandBuffer>> queriesInFlight;
488911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
489011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto cmdBuffer : dev_data->globalInFlightCmdBuffers) {
489111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto pCB = getCBNode(dev_data, cmdBuffer);
489211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (auto queryStatePair : pCB->queryToStateMap) {
489311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            queriesInFlight[queryStatePair.first].push_back(cmdBuffer);
489411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
489511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
489611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
489711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < queryCount; ++i) {
489811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        QueryObject query = {queryPool, firstQuery + i};
489911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto queryElement = queriesInFlight.find(query);
490011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto queryToStateElement = dev_data->queryToStateMap.find(query);
490111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (queryToStateElement != dev_data->queryToStateMap.end()) {
490211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // Available and in flight
490311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (queryElement != queriesInFlight.end() && queryToStateElement != dev_data->queryToStateMap.end() &&
490411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                queryToStateElement->second) {
490511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                for (auto cmdBuffer : queryElement->second) {
490611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    auto pCB = getCBNode(dev_data, cmdBuffer);
490711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    auto queryEventElement = pCB->waitedEventsBeforeQueryReset.find(query);
490811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    if (queryEventElement == pCB->waitedEventsBeforeQueryReset.end()) {
490911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
491011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                             VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
491111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                             "Cannot get query results on queryPool 0x%" PRIx64 " with index %d which is in flight.",
491211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                             (uint64_t)(queryPool), firstQuery + i);
491311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    } else {
491411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        for (auto event : queryEventElement->second) {
491511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            dev_data->eventMap[event].needsSignaled = true;
491611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        }
491711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    }
491811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
491911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                // Unavailable and in flight
492011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            } else if (queryElement != queriesInFlight.end() && queryToStateElement != dev_data->queryToStateMap.end() &&
492111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                       !queryToStateElement->second) {
492211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                // TODO : Can there be the same query in use by multiple command buffers in flight?
492311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                bool make_available = false;
492411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                for (auto cmdBuffer : queryElement->second) {
492511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    auto pCB = getCBNode(dev_data, cmdBuffer);
492611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    make_available |= pCB->queryToStateMap[query];
492711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
492811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (!(((flags & VK_QUERY_RESULT_PARTIAL_BIT) || (flags & VK_QUERY_RESULT_WAIT_BIT)) && make_available)) {
492911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
493011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
493111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         "Cannot get query results on queryPool 0x%" PRIx64 " with index %d which is unavailable.",
493211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         (uint64_t)(queryPool), firstQuery + i);
493311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
493411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                // Unavailable
493511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            } else if (queryToStateElement != dev_data->queryToStateMap.end() && !queryToStateElement->second) {
493611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
493711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                     VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
493811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                     "Cannot get query results on queryPool 0x%" PRIx64 " with index %d which is unavailable.",
493911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                     (uint64_t)(queryPool), firstQuery + i);
494011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                // Unitialized
494111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            } else if (queryToStateElement == dev_data->queryToStateMap.end()) {
494211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
494311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                     VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
494411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                     "Cannot get query results on queryPool 0x%" PRIx64
494511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                     " with index %d as data has not been collected for this index.",
494611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                     (uint64_t)(queryPool), firstQuery + i);
494711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
494811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
494911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
495011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
495111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (skip_call)
495211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return VK_ERROR_VALIDATION_FAILED_EXT;
495311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return dev_data->device_dispatch_table->GetQueryPoolResults(device, queryPool, firstQuery, queryCount, dataSize, pData, stride,
495411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                flags);
495511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
495611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
495711cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validateIdleBuffer(const layer_data *my_data, VkBuffer buffer) {
495811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
495911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto buffer_data = my_data->bufferMap.find(buffer);
496011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (buffer_data == my_data->bufferMap.end()) {
496111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
496211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             (uint64_t)(buffer), __LINE__, DRAWSTATE_DOUBLE_DESTROY, "DS",
496311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             "Cannot free buffer 0x%" PRIxLEAST64 " that has not been allocated.", (uint64_t)(buffer));
496411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else {
496511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (buffer_data->second.in_use.load()) {
496611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
496711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 (uint64_t)(buffer), __LINE__, DRAWSTATE_OBJECT_INUSE, "DS",
496811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 "Cannot free buffer 0x%" PRIxLEAST64 " that is in use by a command buffer.", (uint64_t)(buffer));
496911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
497011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
497111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skip_call;
497211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
497311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
497411cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool print_memory_range_error(layer_data *dev_data, const uint64_t object_handle, const uint64_t other_handle,
497511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                     VkDebugReportObjectTypeEXT object_type) {
497611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (object_type == VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT) {
497711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, object_type, object_handle, 0,
497811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                       MEMTRACK_INVALID_ALIASING, "MEM", "Buffer 0x%" PRIx64 " is aliased with image 0x%" PRIx64, object_handle,
497911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                       other_handle);
498011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else {
498111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, object_type, object_handle, 0,
498211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                       MEMTRACK_INVALID_ALIASING, "MEM", "Image 0x%" PRIx64 " is aliased with buffer 0x%" PRIx64, object_handle,
498311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                       other_handle);
498411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
498511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
498611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
498711cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validate_memory_range(layer_data *dev_data, const vector<MEMORY_RANGE> &ranges, const MEMORY_RANGE &new_range,
498811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                  VkDebugReportObjectTypeEXT object_type) {
498911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
499011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
499111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto range : ranges) {
499211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if ((range.end & ~(dev_data->phys_dev_properties.properties.limits.bufferImageGranularity - 1)) <
499311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            (new_range.start & ~(dev_data->phys_dev_properties.properties.limits.bufferImageGranularity - 1)))
499411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            continue;
499511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if ((range.start & ~(dev_data->phys_dev_properties.properties.limits.bufferImageGranularity - 1)) >
499611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            (new_range.end & ~(dev_data->phys_dev_properties.properties.limits.bufferImageGranularity - 1)))
499711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            continue;
499811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= print_memory_range_error(dev_data, new_range.handle, range.handle, object_type);
499911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
500011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skip_call;
500111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
500211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
500311cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic MEMORY_RANGE insert_memory_ranges(uint64_t handle, VkDeviceMemory mem, VkDeviceSize memoryOffset,
500411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         VkMemoryRequirements memRequirements, vector<MEMORY_RANGE> &ranges) {
500511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    MEMORY_RANGE range;
500611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    range.handle = handle;
500711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    range.memory = mem;
500811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    range.start = memoryOffset;
500911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    range.end = memoryOffset + memRequirements.size - 1;
501011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    ranges.push_back(range);
501111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return range;
501211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
501311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
501411cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void remove_memory_ranges(uint64_t handle, VkDeviceMemory mem, vector<MEMORY_RANGE> &ranges) {
501511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t item = 0; item < ranges.size(); item++) {
501611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if ((ranges[item].handle == handle) && (ranges[item].memory == mem)) {
501711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            ranges.erase(ranges.begin() + item);
501811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            break;
501911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
502011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
502111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
502211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
502311cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL DestroyBuffer(VkDevice device, VkBuffer buffer,
502411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         const VkAllocationCallbacks *pAllocator) {
502511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
502611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
502711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
502811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!validateIdleBuffer(dev_data, buffer) && !skipCall) {
502911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        lock.unlock();
503011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->DestroyBuffer(device, buffer, pAllocator);
503111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        lock.lock();
503211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
503311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Clean up memory binding and range information for buffer
503411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    const auto &bufferEntry = dev_data->bufferMap.find(buffer);
503511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (bufferEntry != dev_data->bufferMap.end()) {
503611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        const auto &memEntry = dev_data->memObjMap.find(bufferEntry->second.mem);
503711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (memEntry != dev_data->memObjMap.end()) {
503811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            remove_memory_ranges(reinterpret_cast<uint64_t &>(buffer), bufferEntry->second.mem, memEntry->second.bufferRanges);
503911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
504011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        clear_object_binding(dev_data, reinterpret_cast<uint64_t &>(buffer), VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT);
504111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->bufferMap.erase(bufferEntry);
504211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
504311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
504411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
504511cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
504611cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertDestroyBufferView(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks *pAllocator) {
504711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
504811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    dev_data->device_dispatch_table->DestroyBufferView(device, bufferView, pAllocator);
504911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::lock_guard<std::mutex> lock(global_lock);
505011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto item = dev_data->bufferViewMap.find(bufferView);
505111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (item != dev_data->bufferViewMap.end()) {
505211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->bufferViewMap.erase(item);
505311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
505411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
505511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
505611cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL DestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) {
505711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
505811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
505911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall) {
506011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->DestroyImage(device, image, pAllocator);
506111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
506211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
506311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::lock_guard<std::mutex> lock(global_lock);
506411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    const auto &imageEntry = dev_data->imageMap.find(image);
506511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (imageEntry != dev_data->imageMap.end()) {
506611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Clean up memory mapping, bindings and range references for image
506711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto memEntry = dev_data->memObjMap.find(imageEntry->second.mem);
506811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (memEntry != dev_data->memObjMap.end()) {
506911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            remove_memory_ranges(reinterpret_cast<uint64_t &>(image), imageEntry->second.mem, memEntry->second.imageRanges);
507011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            clear_object_binding(dev_data, reinterpret_cast<uint64_t &>(image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT);
507111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            memEntry->second.image = VK_NULL_HANDLE;
507211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
507311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Remove image from imageMap
507411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->imageMap.erase(imageEntry);
507511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
507611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    const auto& subEntry = dev_data->imageSubresourceMap.find(image);
507711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (subEntry != dev_data->imageSubresourceMap.end()) {
507811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (const auto& pair : subEntry->second) {
507911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            dev_data->imageLayoutMap.erase(pair);
508011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
508111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->imageSubresourceMap.erase(subEntry);
508211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
508311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
508411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
508511cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL
508611cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertBindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
508711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
508811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
508911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
509011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Track objects tied to memory
509111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    uint64_t buffer_handle = (uint64_t)(buffer);
509211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall =
509311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        set_mem_binding(dev_data, mem, buffer_handle, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, "vkBindBufferMemory");
509411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto buffer_node = dev_data->bufferMap.find(buffer);
509511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (buffer_node != dev_data->bufferMap.end()) {
509611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        buffer_node->second.mem = mem;
509711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        VkMemoryRequirements memRequirements;
509811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->GetBufferMemoryRequirements(device, buffer, &memRequirements);
509911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
510011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Track and validate bound memory range information
510111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        const auto &memEntry = dev_data->memObjMap.find(mem);
510211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (memEntry != dev_data->memObjMap.end()) {
510311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            const MEMORY_RANGE range =
510411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                insert_memory_ranges(buffer_handle, mem, memoryOffset, memRequirements, memEntry->second.bufferRanges);
510511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |=
510611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                validate_memory_range(dev_data, memEntry->second.imageRanges, range, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT);
510711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
510811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
510911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Validate memory requirements alignment
511011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (vk_safe_modulo(memoryOffset, memRequirements.alignment) != 0) {
511111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |=
511211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0,
511311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        __LINE__, DRAWSTATE_INVALID_BUFFER_MEMORY_OFFSET, "DS",
511411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "vkBindBufferMemory(): memoryOffset is 0x%" PRIxLEAST64 " but must be an integer multiple of the "
511511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "VkMemoryRequirements::alignment value 0x%" PRIxLEAST64
511611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        ", returned from a call to vkGetBufferMemoryRequirements with buffer",
511711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        memoryOffset, memRequirements.alignment);
511811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
511911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Validate device limits alignments
512011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        VkBufferUsageFlags usage = dev_data->bufferMap[buffer].createInfo.usage;
512111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (usage & (VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT)) {
512211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (vk_safe_modulo(memoryOffset, dev_data->phys_dev_properties.properties.limits.minTexelBufferOffsetAlignment) != 0) {
512311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skipCall |=
512411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
512511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            0, __LINE__, DRAWSTATE_INVALID_TEXEL_BUFFER_OFFSET, "DS",
512611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "vkBindBufferMemory(): memoryOffset is 0x%" PRIxLEAST64 " but must be a multiple of "
512711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "device limit minTexelBufferOffsetAlignment 0x%" PRIxLEAST64,
512811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            memoryOffset, dev_data->phys_dev_properties.properties.limits.minTexelBufferOffsetAlignment);
512911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
513011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
513111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) {
513211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (vk_safe_modulo(memoryOffset, dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment) !=
513311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                0) {
513411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skipCall |=
513511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
513611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            0, __LINE__, DRAWSTATE_INVALID_UNIFORM_BUFFER_OFFSET, "DS",
513711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "vkBindBufferMemory(): memoryOffset is 0x%" PRIxLEAST64 " but must be a multiple of "
513811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "device limit minUniformBufferOffsetAlignment 0x%" PRIxLEAST64,
513911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            memoryOffset, dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment);
514011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
514111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
514211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) {
514311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (vk_safe_modulo(memoryOffset, dev_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment) !=
514411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                0) {
514511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skipCall |=
514611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
514711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            0, __LINE__, DRAWSTATE_INVALID_STORAGE_BUFFER_OFFSET, "DS",
514811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "vkBindBufferMemory(): memoryOffset is 0x%" PRIxLEAST64 " but must be a multiple of "
514911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "device limit minStorageBufferOffsetAlignment 0x%" PRIxLEAST64,
515011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            memoryOffset, dev_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment);
515111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
515211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
515311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
515411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    print_mem_list(dev_data);
515511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
515611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall) {
515711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        result = dev_data->device_dispatch_table->BindBufferMemory(device, buffer, mem, memoryOffset);
515811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
515911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
516011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
516111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
516211cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
516311cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertGetBufferMemoryRequirements(VkDevice device, VkBuffer buffer, VkMemoryRequirements *pMemoryRequirements) {
516411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
516511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODO : What to track here?
516611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    //   Could potentially save returned mem requirements and validate values passed into BindBufferMemory
516711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    my_data->device_dispatch_table->GetBufferMemoryRequirements(device, buffer, pMemoryRequirements);
516811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
516911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
517011cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
517111cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertGetImageMemoryRequirements(VkDevice device, VkImage image, VkMemoryRequirements *pMemoryRequirements) {
517211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
517311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODO : What to track here?
517411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    //   Could potentially save returned mem requirements and validate values passed into BindImageMemory
517511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    my_data->device_dispatch_table->GetImageMemoryRequirements(device, image, pMemoryRequirements);
517611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
517711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
517811cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
517911cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertDestroyImageView(VkDevice device, VkImageView imageView, const VkAllocationCallbacks *pAllocator) {
518011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    get_my_data_ptr(get_dispatch_key(device), layer_data_map)
518111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        ->device_dispatch_table->DestroyImageView(device, imageView, pAllocator);
518211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODO : Clean up any internal data structures using this obj.
518311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
518411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
518511cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
518611cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertDestroyShaderModule(VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks *pAllocator) {
518711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
518811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
518911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
519011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    my_data->shaderModuleMap.erase(shaderModule);
519111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
519211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
519311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    my_data->device_dispatch_table->DestroyShaderModule(device, shaderModule, pAllocator);
519411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
519511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
519611cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
519711cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertDestroyPipeline(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks *pAllocator) {
519811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    get_my_data_ptr(get_dispatch_key(device), layer_data_map)->device_dispatch_table->DestroyPipeline(device, pipeline, pAllocator);
519911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODO : Clean up any internal data structures using this obj.
520011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
520111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
520211cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
520311cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertDestroyPipelineLayout(VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks *pAllocator) {
520411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    get_my_data_ptr(get_dispatch_key(device), layer_data_map)
520511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        ->device_dispatch_table->DestroyPipelineLayout(device, pipelineLayout, pAllocator);
520611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODO : Clean up any internal data structures using this obj.
520711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
520811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
520911cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
521011cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertDestroySampler(VkDevice device, VkSampler sampler, const VkAllocationCallbacks *pAllocator) {
521111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    get_my_data_ptr(get_dispatch_key(device), layer_data_map)->device_dispatch_table->DestroySampler(device, sampler, pAllocator);
521211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODO : Clean up any internal data structures using this obj.
521311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
521411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
521511cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
521611cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertDestroyDescriptorSetLayout(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks *pAllocator) {
521711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    get_my_data_ptr(get_dispatch_key(device), layer_data_map)
521811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        ->device_dispatch_table->DestroyDescriptorSetLayout(device, descriptorSetLayout, pAllocator);
521911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODO : Clean up any internal data structures using this obj.
522011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
522111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
522211cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
522311cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertDestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks *pAllocator) {
522411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    get_my_data_ptr(get_dispatch_key(device), layer_data_map)
522511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        ->device_dispatch_table->DestroyDescriptorPool(device, descriptorPool, pAllocator);
522611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODO : Clean up any internal data structures using this obj.
522711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
522811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Verify cmdBuffer in given cb_node is not in global in-flight set, and return skip_call result
522911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//  If this is a secondary command buffer, then make sure its primary is also in-flight
523011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//  If primary is not in-flight, then remove secondary from global in-flight set
523111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// This function is only valid at a point when cmdBuffer is being reset or freed
523211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool checkAndClearCommandBufferInFlight(layer_data *dev_data, const GLOBAL_CB_NODE *cb_node, const char *action) {
523311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
523411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (dev_data->globalInFlightCmdBuffers.count(cb_node->commandBuffer)) {
523511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Primary CB or secondary where primary is also in-flight is an error
523611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if ((cb_node->createInfo.level != VK_COMMAND_BUFFER_LEVEL_SECONDARY) ||
523711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            (dev_data->globalInFlightCmdBuffers.count(cb_node->primaryCommandBuffer))) {
523811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |= log_msg(
523911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
524011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                reinterpret_cast<const uint64_t &>(cb_node->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER_RESET, "DS",
524111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                "Attempt to %s command buffer (0x%" PRIxLEAST64 ") which is in use.", action,
524211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                reinterpret_cast<const uint64_t &>(cb_node->commandBuffer));
524311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else { // Secondary CB w/o primary in-flight, remove from in-flight
524411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            dev_data->globalInFlightCmdBuffers.erase(cb_node->commandBuffer);
524511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
524611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
524711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skip_call;
524811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
524911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Iterate over all cmdBuffers in given commandPool and verify that each is not in use
525011cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool checkAndClearCommandBuffersInFlight(layer_data *dev_data, const VkCommandPool commandPool, const char *action) {
525111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
525211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto pool_data = dev_data->commandPoolMap.find(commandPool);
525311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pool_data != dev_data->commandPoolMap.end()) {
525411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (auto cmd_buffer : pool_data->second.commandBuffers) {
525511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (dev_data->globalInFlightCmdBuffers.count(cmd_buffer)) {
525611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skip_call |= checkAndClearCommandBufferInFlight(dev_data, getCBNode(dev_data, cmd_buffer), action);
525711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
525811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
525911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
526011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skip_call;
526111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
526211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
526311cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
526411cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer *pCommandBuffers) {
526511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
526611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
526711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
526811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
526911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < commandBufferCount; i++) {
527011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto cb_pair = dev_data->commandBufferMap.find(pCommandBuffers[i]);
527111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= checkAndClearCommandBufferInFlight(dev_data, cb_pair->second, "free");
527211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Delete CB information structure, and remove from commandBufferMap
527311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (cb_pair != dev_data->commandBufferMap.end()) {
527411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // reset prior to delete for data clean-up
527511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            resetCB(dev_data, (*cb_pair).second->commandBuffer);
527611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            delete (*cb_pair).second;
527711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            dev_data->commandBufferMap.erase(cb_pair);
527811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
527911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
528011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Remove commandBuffer reference from commandPoolMap
528111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->commandPoolMap[commandPool].commandBuffers.remove(pCommandBuffers[i]);
528211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
528311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    printCBList(dev_data);
528411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
528511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
528611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skip_call)
528711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->FreeCommandBuffers(device, commandPool, commandBufferCount, pCommandBuffers);
528811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
528911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
529011cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL CreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo *pCreateInfo,
529111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                 const VkAllocationCallbacks *pAllocator,
529211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                 VkCommandPool *pCommandPool) {
529311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
529411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
529511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = dev_data->device_dispatch_table->CreateCommandPool(device, pCreateInfo, pAllocator, pCommandPool);
529611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
529711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (VK_SUCCESS == result) {
529811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::lock_guard<std::mutex> lock(global_lock);
529911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->commandPoolMap[*pCommandPool].createFlags = pCreateInfo->flags;
530011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->commandPoolMap[*pCommandPool].queueFamilyIndex = pCreateInfo->queueFamilyIndex;
530111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
530211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
530311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
530411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
530511cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL CreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo *pCreateInfo,
530611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                               const VkAllocationCallbacks *pAllocator, VkQueryPool *pQueryPool) {
530711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
530811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
530911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = dev_data->device_dispatch_table->CreateQueryPool(device, pCreateInfo, pAllocator, pQueryPool);
531011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (result == VK_SUCCESS) {
531111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::lock_guard<std::mutex> lock(global_lock);
531211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->queryPoolMap[*pQueryPool].createInfo = *pCreateInfo;
531311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
531411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
531511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
531611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
531711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Destroy commandPool along with all of the commandBuffers allocated from that pool
531811cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
531911cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertDestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks *pAllocator) {
532011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
532111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
532211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
532311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Verify that command buffers in pool are complete (not in-flight)
532411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkBool32 result = checkAndClearCommandBuffersInFlight(dev_data, commandPool, "destroy command pool with");
532511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Must remove cmdpool from cmdpoolmap, after removing all cmdbuffers in its list from the commandPoolMap
532611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto pool_it = dev_data->commandPoolMap.find(commandPool);
532711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pool_it != dev_data->commandPoolMap.end()) {
532811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (auto cb : pool_it->second.commandBuffers) {
532911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            clear_cmd_buf_and_mem_references(dev_data, cb);
533011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            auto del_cb = dev_data->commandBufferMap.find(cb);
533111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            delete del_cb->second;                  // delete CB info structure
533211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            dev_data->commandBufferMap.erase(del_cb); // Remove this command buffer
533311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
533411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
533511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    dev_data->commandPoolMap.erase(commandPool);
533611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
533711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
533811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
533911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (result)
534011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return;
534111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
534211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
534311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->DestroyCommandPool(device, commandPool, pAllocator);
534411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
534511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
534611cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL
534711cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags) {
534811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
534911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
535011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
535111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
535211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (checkAndClearCommandBuffersInFlight(dev_data, commandPool, "reset command pool with"))
535311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return VK_ERROR_VALIDATION_FAILED_EXT;
535411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
535511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
535611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        result = dev_data->device_dispatch_table->ResetCommandPool(device, commandPool, flags);
535711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
535811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Reset all of the CBs allocated from this pool
535911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (VK_SUCCESS == result) {
536011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::lock_guard<std::mutex> lock(global_lock);
536111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto it = dev_data->commandPoolMap[commandPool].commandBuffers.begin();
536211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        while (it != dev_data->commandPoolMap[commandPool].commandBuffers.end()) {
536311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            resetCB(dev_data, (*it));
536411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            ++it;
536511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
536611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
536711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
536811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
536911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
537011cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL ResetFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences) {
537111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
537211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
537311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
537411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
537511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < fenceCount; ++i) {
537611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto fence_item = dev_data->fenceMap.find(pFences[i]);
537711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (fence_item != dev_data->fenceMap.end()) {
537811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            fence_item->second.needsSignaled = true;
537911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            fence_item->second.queues.clear();
538011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            fence_item->second.priorFences.clear();
538111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (fence_item->second.in_use.load()) {
538211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skipCall |=
538311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
538411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            reinterpret_cast<const uint64_t &>(pFences[i]), __LINE__, DRAWSTATE_INVALID_FENCE, "DS",
538511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "Fence 0x%" PRIx64 " is in use by a command buffer.", reinterpret_cast<const uint64_t &>(pFences[i]));
538611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
538711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
538811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
538911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
539011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
539111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        result = dev_data->device_dispatch_table->ResetFences(device, fenceCount, pFences);
539211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
539311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
539411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
539511cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
539611cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertDestroyFramebuffer(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks *pAllocator) {
539711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
539811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
539911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto fbNode = dev_data->frameBufferMap.find(framebuffer);
540011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (fbNode != dev_data->frameBufferMap.end()) {
540111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (auto cb : fbNode->second.referencingCmdBuffers) {
540211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            auto cbNode = dev_data->commandBufferMap.find(cb);
540311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (cbNode != dev_data->commandBufferMap.end()) {
540411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                // Set CB as invalid and record destroyed framebuffer
540511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                cbNode->second->state = CB_INVALID;
540611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                cbNode->second->destroyedFramebuffers.insert(framebuffer);
540711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
540811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
540911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        delete [] fbNode->second.createInfo.pAttachments;
541011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->frameBufferMap.erase(fbNode);
541111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
541211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
541311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    dev_data->device_dispatch_table->DestroyFramebuffer(device, framebuffer, pAllocator);
541411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
541511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
541611cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
541711cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertDestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks *pAllocator) {
541811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
541911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    dev_data->device_dispatch_table->DestroyRenderPass(device, renderPass, pAllocator);
542011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::lock_guard<std::mutex> lock(global_lock);
542111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    dev_data->renderPassMap.erase(renderPass);
542211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
542311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
542411cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL CreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo,
542511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer) {
542611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
542711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
542811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = dev_data->device_dispatch_table->CreateBuffer(device, pCreateInfo, pAllocator, pBuffer);
542911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
543011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (VK_SUCCESS == result) {
543111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::lock_guard<std::mutex> lock(global_lock);
543211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // TODO : This doesn't create deep copy of pQueueFamilyIndices so need to fix that if/when we want that data to be valid
543311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->bufferMap.insert(std::make_pair(*pBuffer, BUFFER_NODE(pCreateInfo)));
543411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
543511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
543611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
543711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
543811cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL CreateBufferView(VkDevice device, const VkBufferViewCreateInfo *pCreateInfo,
543911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                const VkAllocationCallbacks *pAllocator, VkBufferView *pView) {
544011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
544111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = dev_data->device_dispatch_table->CreateBufferView(device, pCreateInfo, pAllocator, pView);
544211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (VK_SUCCESS == result) {
544311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::lock_guard<std::mutex> lock(global_lock);
544411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->bufferViewMap[*pView] = VkBufferViewCreateInfo(*pCreateInfo);
544511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // In order to create a valid buffer view, the buffer must have been created with at least one of the
544611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // following flags:  UNIFORM_TEXEL_BUFFER_BIT or STORAGE_TEXEL_BUFFER_BIT
544711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        validate_buffer_usage_flags(dev_data, pCreateInfo->buffer,
544811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT, false,
544911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    "vkCreateBufferView()", "VK_BUFFER_USAGE_[STORAGE|UNIFORM]_TEXEL_BUFFER_BIT");
545011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
545111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
545211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
545311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
545411cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL CreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo,
545511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                           const VkAllocationCallbacks *pAllocator, VkImage *pImage) {
545611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
545711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
545811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = dev_data->device_dispatch_table->CreateImage(device, pCreateInfo, pAllocator, pImage);
545911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
546011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (VK_SUCCESS == result) {
546111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::lock_guard<std::mutex> lock(global_lock);
546211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        IMAGE_LAYOUT_NODE image_node;
546311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        image_node.layout = pCreateInfo->initialLayout;
546411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        image_node.format = pCreateInfo->format;
546511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->imageMap.insert(std::make_pair(*pImage, IMAGE_NODE(pCreateInfo)));
546611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        ImageSubresourcePair subpair = {*pImage, false, VkImageSubresource()};
546711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->imageSubresourceMap[*pImage].push_back(subpair);
546811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->imageLayoutMap[subpair] = image_node;
546911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
547011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
547111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
547211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
547311cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void ResolveRemainingLevelsLayers(layer_data *dev_data, VkImageSubresourceRange *range, VkImage image) {
547411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    /* expects global_lock to be held by caller */
547511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
547611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto image_node_it = dev_data->imageMap.find(image);
547711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (image_node_it != dev_data->imageMap.end()) {
547811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        /* If the caller used the special values VK_REMAINING_MIP_LEVELS and
547911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert         * VK_REMAINING_ARRAY_LAYERS, resolve them now in our internal state to
548011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert         * the actual values.
548111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert         */
548211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (range->levelCount == VK_REMAINING_MIP_LEVELS) {
548311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            range->levelCount = image_node_it->second.createInfo.mipLevels - range->baseMipLevel;
548411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
548511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
548611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (range->layerCount == VK_REMAINING_ARRAY_LAYERS) {
548711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            range->layerCount = image_node_it->second.createInfo.arrayLayers - range->baseArrayLayer;
548811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
548911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
549011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
549111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
549211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Return the correct layer/level counts if the caller used the special
549311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// values VK_REMAINING_MIP_LEVELS or VK_REMAINING_ARRAY_LAYERS.
549411cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void ResolveRemainingLevelsLayers(layer_data *dev_data, uint32_t *levels, uint32_t *layers, VkImageSubresourceRange range,
549511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         VkImage image) {
549611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    /* expects global_lock to be held by caller */
549711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
549811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    *levels = range.levelCount;
549911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    *layers = range.layerCount;
550011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto image_node_it = dev_data->imageMap.find(image);
550111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (image_node_it != dev_data->imageMap.end()) {
550211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (range.levelCount == VK_REMAINING_MIP_LEVELS) {
550311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            *levels = image_node_it->second.createInfo.mipLevels - range.baseMipLevel;
550411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
550511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (range.layerCount == VK_REMAINING_ARRAY_LAYERS) {
550611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            *layers = image_node_it->second.createInfo.arrayLayers - range.baseArrayLayer;
550711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
550811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
550911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
551011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
551111cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL CreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo,
551211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                               const VkAllocationCallbacks *pAllocator, VkImageView *pView) {
551311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
551411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
551511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
551611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    {
551711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Validate that img has correct usage flags set
551811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::lock_guard<std::mutex> lock(global_lock);
551911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= validate_image_usage_flags(dev_data, pCreateInfo->image,
552011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT |
552111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
552211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                false, "vkCreateImageView()", "VK_IMAGE_USAGE_[SAMPLED|STORAGE|COLOR_ATTACHMENT]_BIT");
552311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
552411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
552511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall) {
552611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        result = dev_data->device_dispatch_table->CreateImageView(device, pCreateInfo, pAllocator, pView);
552711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
552811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
552911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (VK_SUCCESS == result) {
553011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::lock_guard<std::mutex> lock(global_lock);
553111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        VkImageViewCreateInfo localCI = VkImageViewCreateInfo(*pCreateInfo);
553211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        ResolveRemainingLevelsLayers(dev_data, &localCI.subresourceRange, pCreateInfo->image);
553311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->imageViewMap[*pView] = localCI;
553411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
553511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
553611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
553711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
553811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
553911cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL
554011cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCreateFence(VkDevice device, const VkFenceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkFence *pFence) {
554111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
554211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = dev_data->device_dispatch_table->CreateFence(device, pCreateInfo, pAllocator, pFence);
554311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (VK_SUCCESS == result) {
554411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::lock_guard<std::mutex> lock(global_lock);
554511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto &fence_node = dev_data->fenceMap[*pFence];
554611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        fence_node.createInfo = *pCreateInfo;
554711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        fence_node.needsSignaled = true;
554811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) {
554911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            fence_node.firstTimeFlag = true;
555011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            fence_node.needsSignaled = false;
555111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
555211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        fence_node.in_use.store(0);
555311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
555411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
555511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
555611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
555711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// TODO handle pipeline caches
555811cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL CreatePipelineCache(VkDevice device, const VkPipelineCacheCreateInfo *pCreateInfo,
555911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                   const VkAllocationCallbacks *pAllocator, VkPipelineCache *pPipelineCache) {
556011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
556111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = dev_data->device_dispatch_table->CreatePipelineCache(device, pCreateInfo, pAllocator, pPipelineCache);
556211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
556311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
556411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
556511cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
556611cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertDestroyPipelineCache(VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks *pAllocator) {
556711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
556811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    dev_data->device_dispatch_table->DestroyPipelineCache(device, pipelineCache, pAllocator);
556911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
557011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
557111cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL
557211cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertGetPipelineCacheData(VkDevice device, VkPipelineCache pipelineCache, size_t *pDataSize, void *pData) {
557311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
557411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = dev_data->device_dispatch_table->GetPipelineCacheData(device, pipelineCache, pDataSize, pData);
557511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
557611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
557711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
557811cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL
557911cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertMergePipelineCaches(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount, const VkPipelineCache *pSrcCaches) {
558011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
558111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = dev_data->device_dispatch_table->MergePipelineCaches(device, dstCache, srcCacheCount, pSrcCaches);
558211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
558311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
558411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
558511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// utility function to set collective state for pipeline
558611cd02dfb91661c65134cac258cf5924270e9d2Dan Albertvoid set_pipeline_state(PIPELINE_NODE *pPipe) {
558711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // If any attachment used by this pipeline has blendEnable, set top-level blendEnable
558811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pPipe->graphicsPipelineCI.pColorBlendState) {
558911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (size_t i = 0; i < pPipe->attachments.size(); ++i) {
559011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (VK_TRUE == pPipe->attachments[i].blendEnable) {
559111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (((pPipe->attachments[i].dstAlphaBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
559211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                     (pPipe->attachments[i].dstAlphaBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
559311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    ((pPipe->attachments[i].dstColorBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
559411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                     (pPipe->attachments[i].dstColorBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
559511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    ((pPipe->attachments[i].srcAlphaBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
559611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                     (pPipe->attachments[i].srcAlphaBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
559711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    ((pPipe->attachments[i].srcColorBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
559811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                     (pPipe->attachments[i].srcColorBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA))) {
559911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    pPipe->blendConstantsEnabled = true;
560011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
560111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
560211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
560311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
560411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
560511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
560611cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL
560711cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
560811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        const VkGraphicsPipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator,
560911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        VkPipeline *pPipelines) {
561011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = VK_SUCCESS;
561111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODO What to do with pipelineCache?
561211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // The order of operations here is a little convoluted but gets the job done
561311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    //  1. Pipeline create state is first shadowed into PIPELINE_NODE struct
561411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    //  2. Create state is then validated (which uses flags setup during shadowing)
561511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    //  3. If everything looks good, we'll then create the pipeline and add NODE to pipelineMap
561611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
561711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODO : Improve this data struct w/ unique_ptrs so cleanup below is automatic
561811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    vector<PIPELINE_NODE *> pPipeNode(count);
561911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
562011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
562111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    uint32_t i = 0;
562211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
562311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
562411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (i = 0; i < count; i++) {
562511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pPipeNode[i] = new PIPELINE_NODE;
562611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pPipeNode[i]->initGraphicsPipeline(&pCreateInfos[i]);
562711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pPipeNode[i]->renderPass = getRenderPass(dev_data, pCreateInfos[i].renderPass);
562811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pPipeNode[i]->pipelineLayout = getPipelineLayout(dev_data, pCreateInfos[i].layout);
562911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
563011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= verifyPipelineCreateState(dev_data, device, pPipeNode, i);
563111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
563211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
563311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall) {
563411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        lock.unlock();
563511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        result = dev_data->device_dispatch_table->CreateGraphicsPipelines(device, pipelineCache, count, pCreateInfos, pAllocator,
563611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                          pPipelines);
563711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        lock.lock();
563811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (i = 0; i < count; i++) {
563911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pPipeNode[i]->pipeline = pPipelines[i];
564011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            dev_data->pipelineMap[pPipeNode[i]->pipeline] = pPipeNode[i];
564111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
564211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        lock.unlock();
564311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else {
564411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (i = 0; i < count; i++) {
564511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            delete pPipeNode[i];
564611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
564711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        lock.unlock();
564811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return VK_ERROR_VALIDATION_FAILED_EXT;
564911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
565011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
565111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
565211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
565311cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL
565411cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
565511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                       const VkComputePipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator,
565611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                       VkPipeline *pPipelines) {
565711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = VK_SUCCESS;
565811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
565911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
566011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODO : Improve this data struct w/ unique_ptrs so cleanup below is automatic
566111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    vector<PIPELINE_NODE *> pPipeNode(count);
566211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
566311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
566411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    uint32_t i = 0;
566511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
566611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (i = 0; i < count; i++) {
566711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // TODO: Verify compute stage bits
566811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
566911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Create and initialize internal tracking data structure
567011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pPipeNode[i] = new PIPELINE_NODE;
567111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pPipeNode[i]->initComputePipeline(&pCreateInfos[i]);
567211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pPipeNode[i]->pipelineLayout = getPipelineLayout(dev_data, pCreateInfos[i].layout);
567311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // memcpy(&pPipeNode[i]->computePipelineCI, (const void *)&pCreateInfos[i], sizeof(VkComputePipelineCreateInfo));
567411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
567511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // TODO: Add Compute Pipeline Verification
567611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // skipCall |= verifyPipelineCreateState(dev_data, device, pPipeNode[i]);
567711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
567811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
567911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall) {
568011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        lock.unlock();
568111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        result = dev_data->device_dispatch_table->CreateComputePipelines(device, pipelineCache, count, pCreateInfos, pAllocator,
568211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                         pPipelines);
568311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        lock.lock();
568411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (i = 0; i < count; i++) {
568511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pPipeNode[i]->pipeline = pPipelines[i];
568611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            dev_data->pipelineMap[pPipeNode[i]->pipeline] = pPipeNode[i];
568711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
568811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        lock.unlock();
568911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else {
569011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (i = 0; i < count; i++) {
569111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // Clean up any locally allocated data structures
569211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            delete pPipeNode[i];
569311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
569411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        lock.unlock();
569511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return VK_ERROR_VALIDATION_FAILED_EXT;
569611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
569711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
569811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
569911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
570011cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL CreateSampler(VkDevice device, const VkSamplerCreateInfo *pCreateInfo,
570111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                             const VkAllocationCallbacks *pAllocator, VkSampler *pSampler) {
570211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
570311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = dev_data->device_dispatch_table->CreateSampler(device, pCreateInfo, pAllocator, pSampler);
570411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (VK_SUCCESS == result) {
570511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::lock_guard<std::mutex> lock(global_lock);
570611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->samplerMap[*pSampler] = unique_ptr<SAMPLER_NODE>(new SAMPLER_NODE(pSampler, pCreateInfo));
570711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
570811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
570911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
571011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
571111cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL
571211cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
571311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                          const VkAllocationCallbacks *pAllocator, VkDescriptorSetLayout *pSetLayout) {
571411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
571511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = dev_data->device_dispatch_table->CreateDescriptorSetLayout(device, pCreateInfo, pAllocator, pSetLayout);
571611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (VK_SUCCESS == result) {
571711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // TODOSC : Capture layout bindings set
571811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::lock_guard<std::mutex> lock(global_lock);
571911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->descriptorSetLayoutMap[*pSetLayout] =
572011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            new cvdescriptorset::DescriptorSetLayout(dev_data->report_data, pCreateInfo, *pSetLayout);
572111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
572211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
572311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
572411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
572511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Used by CreatePipelineLayout and CmdPushConstants.
572611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Note that the index argument is optional and only used by CreatePipelineLayout.
572711cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validatePushConstantRange(const layer_data *dev_data, const uint32_t offset, const uint32_t size,
572811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                      const char *caller_name, uint32_t index = 0) {
572911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    uint32_t const maxPushConstantsSize = dev_data->phys_dev_properties.properties.limits.maxPushConstantsSize;
573011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
573111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Check that offset + size don't exceed the max.
573211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Prevent arithetic overflow here by avoiding addition and testing in this order.
573311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if ((offset >= maxPushConstantsSize) || (size > maxPushConstantsSize - offset)) {
573411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // This is a pain just to adapt the log message to the caller, but better to sort it out only when there is a problem.
573511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (0 == strcmp(caller_name, "vkCreatePipelineLayout()")) {
573611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |=
573711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
573811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        DRAWSTATE_PUSH_CONSTANTS_ERROR, "DS", "%s call has push constants index %u with offset %u and size %u that "
573911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                              "exceeds this device's maxPushConstantSize of %u.",
574011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        caller_name, index, offset, size, maxPushConstantsSize);
574111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else if (0 == strcmp(caller_name, "vkCmdPushConstants()")) {
574211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
574311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                DRAWSTATE_PUSH_CONSTANTS_ERROR, "DS", "%s call has push constants with offset %u and size %u that "
574411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                      "exceeds this device's maxPushConstantSize of %u.",
574511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                caller_name, offset, size, maxPushConstantsSize);
574611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
574711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
574811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                DRAWSTATE_INTERNAL_ERROR, "DS", "%s caller not supported.", caller_name);
574911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
575011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
575111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // size needs to be non-zero and a multiple of 4.
575211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if ((size == 0) || ((size & 0x3) != 0)) {
575311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (0 == strcmp(caller_name, "vkCreatePipelineLayout()")) {
575411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |=
575511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
575611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        DRAWSTATE_PUSH_CONSTANTS_ERROR, "DS", "%s call has push constants index %u with "
575711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                              "size %u. Size must be greater than zero and a multiple of 4.",
575811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        caller_name, index, size);
575911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else if (0 == strcmp(caller_name, "vkCmdPushConstants()")) {
576011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |=
576111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
576211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        DRAWSTATE_PUSH_CONSTANTS_ERROR, "DS", "%s call has push constants with "
576311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                              "size %u. Size must be greater than zero and a multiple of 4.",
576411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        caller_name, size);
576511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
576611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
576711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                DRAWSTATE_INTERNAL_ERROR, "DS", "%s caller not supported.", caller_name);
576811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
576911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
577011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // offset needs to be a multiple of 4.
577111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if ((offset & 0x3) != 0) {
577211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (0 == strcmp(caller_name, "vkCreatePipelineLayout()")) {
577311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
577411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                DRAWSTATE_PUSH_CONSTANTS_ERROR, "DS", "%s call has push constants index %u with "
577511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                      "offset %u. Offset must be a multiple of 4.",
577611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                caller_name, index, offset);
577711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else if (0 == strcmp(caller_name, "vkCmdPushConstants()")) {
577811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
577911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                DRAWSTATE_PUSH_CONSTANTS_ERROR, "DS", "%s call has push constants with "
578011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                      "offset %u. Offset must be a multiple of 4.",
578111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                caller_name, offset);
578211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
578311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
578411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                DRAWSTATE_INTERNAL_ERROR, "DS", "%s caller not supported.", caller_name);
578511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
578611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
578711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skipCall;
578811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
578911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
579011cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL CreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo *pCreateInfo,
579111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                    const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout) {
579211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
579311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
579411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Push Constant Range checks
579511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    uint32_t i = 0;
579611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
579711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= validatePushConstantRange(dev_data, pCreateInfo->pPushConstantRanges[i].offset,
579811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                              pCreateInfo->pPushConstantRanges[i].size, "vkCreatePipelineLayout()", i);
579911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (0 == pCreateInfo->pPushConstantRanges[i].stageFlags) {
580011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
580111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                DRAWSTATE_PUSH_CONSTANTS_ERROR, "DS", "vkCreatePipelineLayout() call has no stageFlags set.");
580211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
580311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
580411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Each range has been validated.  Now check for overlap between ranges (if they are good).
580511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall) {
580611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        uint32_t i, j;
580711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
580811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (j = i + 1; j < pCreateInfo->pushConstantRangeCount; ++j) {
580911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                const uint32_t minA = pCreateInfo->pPushConstantRanges[i].offset;
581011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                const uint32_t maxA = minA + pCreateInfo->pPushConstantRanges[i].size;
581111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                const uint32_t minB = pCreateInfo->pPushConstantRanges[j].offset;
581211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                const uint32_t maxB = minB + pCreateInfo->pPushConstantRanges[j].size;
581311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if ((minA <= minB && maxA > minB) || (minB <= minA && maxB > minA)) {
581411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skipCall |=
581511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
581611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                DRAWSTATE_PUSH_CONSTANTS_ERROR, "DS", "vkCreatePipelineLayout() call has push constants with "
581711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                      "overlapping ranges: %u:[%u, %u), %u:[%u, %u)",
581811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                i, minA, maxA, j, minB, maxB);
581911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
582011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
582111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
582211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
582311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
582411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (skipCall)
582511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return VK_ERROR_VALIDATION_FAILED_EXT;
582611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
582711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = dev_data->device_dispatch_table->CreatePipelineLayout(device, pCreateInfo, pAllocator, pPipelineLayout);
582811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (VK_SUCCESS == result) {
582911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::lock_guard<std::mutex> lock(global_lock);
583011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        PIPELINE_LAYOUT_NODE &plNode = dev_data->pipelineLayoutMap[*pPipelineLayout];
583111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        plNode.descriptorSetLayouts.resize(pCreateInfo->setLayoutCount);
583211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        plNode.setLayouts.resize(pCreateInfo->setLayoutCount);
583311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (i = 0; i < pCreateInfo->setLayoutCount; ++i) {
583411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            plNode.descriptorSetLayouts[i] = pCreateInfo->pSetLayouts[i];
583511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            plNode.setLayouts[i] = getDescriptorSetLayout(dev_data, pCreateInfo->pSetLayouts[i]);
583611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
583711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        plNode.pushConstantRanges.resize(pCreateInfo->pushConstantRangeCount);
583811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
583911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            plNode.pushConstantRanges[i] = pCreateInfo->pPushConstantRanges[i];
584011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
584111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
584211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
584311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
584411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
584511cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL
584611cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCreateDescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
584711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                     VkDescriptorPool *pDescriptorPool) {
584811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
584911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = dev_data->device_dispatch_table->CreateDescriptorPool(device, pCreateInfo, pAllocator, pDescriptorPool);
585011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (VK_SUCCESS == result) {
585111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Insert this pool into Global Pool LL at head
585211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
585311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    (uint64_t)*pDescriptorPool, __LINE__, DRAWSTATE_OUT_OF_MEMORY, "DS", "Created Descriptor Pool 0x%" PRIxLEAST64,
585411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    (uint64_t)*pDescriptorPool))
585511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return VK_ERROR_VALIDATION_FAILED_EXT;
585611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        DESCRIPTOR_POOL_NODE *pNewNode = new DESCRIPTOR_POOL_NODE(*pDescriptorPool, pCreateInfo);
585711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (NULL == pNewNode) {
585811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
585911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        (uint64_t)*pDescriptorPool, __LINE__, DRAWSTATE_OUT_OF_MEMORY, "DS",
586011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "Out of memory while attempting to allocate DESCRIPTOR_POOL_NODE in vkCreateDescriptorPool()"))
586111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                return VK_ERROR_VALIDATION_FAILED_EXT;
586211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
586311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            std::lock_guard<std::mutex> lock(global_lock);
586411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            dev_data->descriptorPoolMap[*pDescriptorPool] = pNewNode;
586511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
586611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else {
586711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Need to do anything if pool create fails?
586811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
586911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
587011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
587111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
587211cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL
587311cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags) {
587411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
587511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = dev_data->device_dispatch_table->ResetDescriptorPool(device, descriptorPool, flags);
587611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (VK_SUCCESS == result) {
587711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::lock_guard<std::mutex> lock(global_lock);
587811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        clearDescriptorPool(dev_data, device, descriptorPool, flags);
587911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
588011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
588111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
588211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
588311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Ensure the pool contains enough descriptors and descriptor sets to satisfy
588411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// an allocation request. Fills requiredDescriptorsByType with the total number
588511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// of descriptors of each type required, for later update.
588611cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool PreCallValidateAllocateDescriptorSets(layer_data *dev_data, DESCRIPTOR_POOL_NODE *pPoolNode, uint32_t count,
588711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                  std::vector<cvdescriptorset::DescriptorSetLayout const *> const & layout_nodes,
588811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                  uint32_t requiredDescriptorsByType[]) {
588911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
589011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
589111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Track number of descriptorSets allowable in this pool
589211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pPoolNode->availableSets < count) {
589311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
589411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            reinterpret_cast<uint64_t &>(pPoolNode->pool), __LINE__, DRAWSTATE_DESCRIPTOR_POOL_EMPTY, "DS",
589511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "Unable to allocate %u descriptorSets from pool 0x%" PRIxLEAST64
589611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            ". This pool only has %d descriptorSets remaining.",
589711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            count, reinterpret_cast<uint64_t &>(pPoolNode->pool), pPoolNode->availableSets);
589811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
589911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
590011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Count total descriptors required per type
590111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto layout_node : layout_nodes) {
590211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (layout_node) {
590311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (uint32_t j = 0; j < layout_node->GetBindingCount(); ++j) {
590411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                const auto &binding_layout = layout_node->GetDescriptorSetLayoutBindingPtrFromIndex(j);
590511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                uint32_t typeIndex = static_cast<uint32_t>(binding_layout->descriptorType);
590611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                requiredDescriptorsByType[typeIndex] += binding_layout->descriptorCount;
590711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
590811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
590911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
591011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
591111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Determine whether descriptor counts are satisfiable
591211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < VK_DESCRIPTOR_TYPE_RANGE_SIZE; i++) {
591311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (requiredDescriptorsByType[i] > pPoolNode->availableDescriptorTypeCount[i]) {
591411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= log_msg(
591511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
591611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    reinterpret_cast<const uint64_t &>(pPoolNode->pool), __LINE__, DRAWSTATE_DESCRIPTOR_POOL_EMPTY, "DS",
591711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    "Unable to allocate %u descriptors of type %s from pool 0x%" PRIxLEAST64
591811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    ". This pool only has %d descriptors of this type remaining.",
591911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    requiredDescriptorsByType[i], string_VkDescriptorType(VkDescriptorType(i)), (uint64_t)pPoolNode->pool,
592011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    pPoolNode->availableDescriptorTypeCount[i]);
592111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
592211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
592311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
592411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skipCall;
592511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
592611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
592711cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL
592811cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertAllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo, VkDescriptorSet *pDescriptorSets) {
592911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
593011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
593111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
593211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    uint32_t requiredDescriptorsByType[VK_DESCRIPTOR_TYPE_RANGE_SIZE] {};
593311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::vector<cvdescriptorset::DescriptorSetLayout const *> layout_nodes(pAllocateInfo->descriptorSetCount, nullptr);
593411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
593511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
593611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
593711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < pAllocateInfo->descriptorSetCount; i++) {
593811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        layout_nodes[i] = getDescriptorSetLayout(dev_data, pAllocateInfo->pSetLayouts[i]);
593911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!layout_nodes[i]) {
594011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT,
594111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        (uint64_t)pAllocateInfo->pSetLayouts[i], __LINE__, DRAWSTATE_INVALID_LAYOUT, "DS",
594211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "Unable to find set layout node for layout 0x%" PRIxLEAST64 " specified in vkAllocateDescriptorSets() call",
594311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        (uint64_t)pAllocateInfo->pSetLayouts[i]);
594411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
594511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
594611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
594711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    DESCRIPTOR_POOL_NODE *pPoolNode = getPoolNode(dev_data, pAllocateInfo->descriptorPool);
594811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
594911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!pPoolNode) {
595011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
595111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            (uint64_t)pAllocateInfo->descriptorPool, __LINE__, DRAWSTATE_INVALID_POOL, "DS",
595211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "Unable to find pool node for pool 0x%" PRIxLEAST64 " specified in vkAllocateDescriptorSets() call",
595311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            (uint64_t)pAllocateInfo->descriptorPool);
595411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else { // Make sure pool has all the available descriptors before calling down chain
595511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= PreCallValidateAllocateDescriptorSets(dev_data, pPoolNode, pAllocateInfo->descriptorSetCount,
595611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                          layout_nodes, requiredDescriptorsByType);
595711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
595811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
595911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
596011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (skipCall)
596111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return VK_ERROR_VALIDATION_FAILED_EXT;
596211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
596311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = dev_data->device_dispatch_table->AllocateDescriptorSets(device, pAllocateInfo, pDescriptorSets);
596411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
596511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (VK_SUCCESS == result) {
596611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        lock.lock();
596711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (pPoolNode) {
596811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            /* Account for sets and descriptors allocated */
596911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pPoolNode->availableSets -= pAllocateInfo->descriptorSetCount;
597011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (uint32_t i = 0; i < VK_DESCRIPTOR_TYPE_RANGE_SIZE; i++) {
597111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pPoolNode->availableDescriptorTypeCount[i] -= requiredDescriptorsByType[i];
597211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
597311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
597411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            /* Create tracking object for each descriptor set; insert into
597511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert             * global map and the pool's set.
597611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert             */
597711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (uint32_t i = 0; i < pAllocateInfo->descriptorSetCount; i++) {
597811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (layout_nodes[i]) {
597911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    auto pNewNode = new cvdescriptorset::DescriptorSet(
598011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            pDescriptorSets[i], layout_nodes[i], &dev_data->bufferMap, &dev_data->memObjMap, &dev_data->bufferViewMap,
598111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            &dev_data->samplerMap, &dev_data->imageViewMap, &dev_data->imageMap,
598211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            &dev_data->device_extensions.imageToSwapchainMap, &dev_data->device_extensions.swapchainMap);
598311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
598411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    pPoolNode->sets.insert(pNewNode);
598511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    pNewNode->in_use.store(0);
598611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    dev_data->setMap[pDescriptorSets[i]] = pNewNode;
598711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
598811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
598911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
599011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        lock.unlock();
599111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
599211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
599311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
599411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
599511cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL
599611cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertFreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t count, const VkDescriptorSet *pDescriptorSets) {
599711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
599811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
599911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Make sure that no sets being destroyed are in-flight
600011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
600111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < count; ++i)
600211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= validateIdleDescriptorSet(dev_data, pDescriptorSets[i], "vkFreeDescriptorSets");
600311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    DESCRIPTOR_POOL_NODE *pPoolNode = getPoolNode(dev_data, descriptorPool);
600411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pPoolNode && !(VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT & pPoolNode->createInfo.flags)) {
600511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Can't Free from a NON_FREE pool
600611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
600711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            (uint64_t)device, __LINE__, DRAWSTATE_CANT_FREE_FROM_NON_FREE_POOL, "DS",
600811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "It is invalid to call vkFreeDescriptorSets() with a pool created without setting "
600911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT.");
601011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
601111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
601211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (skipCall)
601311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return VK_ERROR_VALIDATION_FAILED_EXT;
601411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = dev_data->device_dispatch_table->FreeDescriptorSets(device, descriptorPool, count, pDescriptorSets);
601511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (VK_SUCCESS == result) {
601611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        lock.lock();
601711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
601811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Update available descriptor sets in pool
601911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pPoolNode->availableSets += count;
602011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
602111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // For each freed descriptor add its resources back into the pool as available and remove from pool and setMap
602211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t i = 0; i < count; ++i) {
602311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            cvdescriptorset::DescriptorSet *pSet = dev_data->setMap[pDescriptorSets[i]]; // getSetNode() without locking
602411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            uint32_t typeIndex = 0, poolSizeCount = 0;
602511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (uint32_t j = 0; j < pSet->GetBindingCount(); ++j) {
602611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                typeIndex = static_cast<uint32_t>(pSet->GetTypeFromIndex(j));
602711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                poolSizeCount = pSet->GetDescriptorCountFromIndex(j);
602811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pPoolNode->availableDescriptorTypeCount[typeIndex] += poolSizeCount;
602911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
603011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            freeDescriptorSet(dev_data, pSet);
603111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pPoolNode->sets.erase(pSet);
603211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
603311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        lock.unlock();
603411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
603511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODO : Any other clean-up or book-keeping to do here?
603611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
603711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
603811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// TODO : This is a Proof-of-concept for core validation architecture
603911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//  Really we'll want to break out these functions to separate files but
604011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert//  keeping it all together here to prove out design
604111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// PreCallValidate* handles validating all of the state prior to calling down chain to UpdateDescriptorSets()
604211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool PreCallValidateUpdateDescriptorSets(layer_data *dev_data, uint32_t descriptorWriteCount,
604311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
604411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                const VkCopyDescriptorSet *pDescriptorCopies) {
604511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // First thing to do is perform map look-ups.
604611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // NOTE : UpdateDescriptorSets is somewhat unique in that it's operating on a number of DescriptorSets
604711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    //  so we can't just do a single map look-up up-front, but do them individually in functions below
604811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
604911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Now make call(s) that validate state, but don't perform state updates in this function
605011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Note, here DescriptorSets is unique in that we don't yet have an instance. Using a helper function in the
605111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    //  namespace which will parse params and make calls into specific class instances
605211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return cvdescriptorset::ValidateUpdateDescriptorSets(dev_data->report_data, dev_data->setMap, descriptorWriteCount,
605311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                         pDescriptorWrites, descriptorCopyCount, pDescriptorCopies);
605411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
605511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// PostCallRecord* handles recording state updates following call down chain to UpdateDescriptorSets()
605611cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void PostCallRecordUpdateDescriptorSets(layer_data *dev_data, uint32_t descriptorWriteCount,
605711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                               const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
605811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                               const VkCopyDescriptorSet *pDescriptorCopies) {
605911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    cvdescriptorset::PerformUpdateDescriptorSets(dev_data->setMap, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
606011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                 pDescriptorCopies);
606111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
606211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
606311cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
606411cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertUpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet *pDescriptorWrites,
606511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                     uint32_t descriptorCopyCount, const VkCopyDescriptorSet *pDescriptorCopies) {
606611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Only map look-up at top level is for device-level layer_data
606711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
606811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
606911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = PreCallValidateUpdateDescriptorSets(dev_data, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
607011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                         pDescriptorCopies);
607111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
607211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skip_call) {
607311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->UpdateDescriptorSets(device, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
607411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                              pDescriptorCopies);
607511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        lock.lock();
607611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Since UpdateDescriptorSets() is void, nothing to check prior to updating state
607711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        PostCallRecordUpdateDescriptorSets(dev_data, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
607811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                           pDescriptorCopies);
607911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
608011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
608111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
608211cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL
608311cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertAllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pCreateInfo, VkCommandBuffer *pCommandBuffer) {
608411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
608511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = dev_data->device_dispatch_table->AllocateCommandBuffers(device, pCreateInfo, pCommandBuffer);
608611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (VK_SUCCESS == result) {
608711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::unique_lock<std::mutex> lock(global_lock);
608811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto const &cp_it = dev_data->commandPoolMap.find(pCreateInfo->commandPool);
608911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (cp_it != dev_data->commandPoolMap.end()) {
609011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (uint32_t i = 0; i < pCreateInfo->commandBufferCount; i++) {
609111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                // Add command buffer to its commandPool map
609211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                cp_it->second.commandBuffers.push_back(pCommandBuffer[i]);
609311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                GLOBAL_CB_NODE *pCB = new GLOBAL_CB_NODE;
609411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                // Add command buffer to map
609511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                dev_data->commandBufferMap[pCommandBuffer[i]] = pCB;
609611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                resetCB(dev_data, pCommandBuffer[i]);
609711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pCB->createInfo = *pCreateInfo;
609811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pCB->device = device;
609911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
610011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
610111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        printCBList(dev_data);
610211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        lock.unlock();
610311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
610411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
610511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
610611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
610711cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL
610811cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertBeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo) {
610911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
611011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
611111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
611211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Validate command buffer level
611311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
611411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
611511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // This implicitly resets the Cmd Buffer so make sure any fence is done and then clear memory references
611611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (dev_data->globalInFlightCmdBuffers.count(commandBuffer)) {
611711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |=
611811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
611911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        (uint64_t)commandBuffer, __LINE__, MEMTRACK_RESET_CB_WHILE_IN_FLIGHT, "MEM",
612011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "Calling vkBeginCommandBuffer() on active CB 0x%p before it has completed. "
612111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "You must check CB fence before this call.",
612211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        commandBuffer);
612311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
612411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        clear_cmd_buf_and_mem_references(dev_data, pCB);
612511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (pCB->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
612611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // Secondary Command Buffer
612711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            const VkCommandBufferInheritanceInfo *pInfo = pBeginInfo->pInheritanceInfo;
612811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (!pInfo) {
612911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skipCall |=
613011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
613111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            reinterpret_cast<uint64_t>(commandBuffer), __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS",
613211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "vkBeginCommandBuffer(): Secondary Command Buffer (0x%p) must have inheritance info.",
613311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            reinterpret_cast<void *>(commandBuffer));
613411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            } else {
613511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (pBeginInfo->flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT) {
613611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    if (!pInfo->renderPass) { // renderpass should NOT be null for a Secondary CB
613711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        skipCall |= log_msg(
613811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
613911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            reinterpret_cast<uint64_t>(commandBuffer), __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS",
614011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "vkBeginCommandBuffer(): Secondary Command Buffers (0x%p) must specify a valid renderpass parameter.",
614111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            reinterpret_cast<void *>(commandBuffer));
614211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    }
614311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    if (!pInfo->framebuffer) { // framebuffer may be null for a Secondary CB, but this affects perf
614411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
614511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
614611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            reinterpret_cast<uint64_t>(commandBuffer), __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE,
614711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            "DS", "vkBeginCommandBuffer(): Secondary Command Buffers (0x%p) may perform better if a "
614811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                  "valid framebuffer parameter is specified.",
614911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            reinterpret_cast<void *>(commandBuffer));
615011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    } else {
615111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        string errorString = "";
615211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        auto framebuffer = getFramebuffer(dev_data, pInfo->framebuffer);
615311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        if (framebuffer) {
615411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            VkRenderPass fbRP = framebuffer->createInfo.renderPass;
615511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            if (!verify_renderpass_compatibility(dev_data, fbRP, pInfo->renderPass, errorString)) {
615611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                // renderPass that framebuffer was created with must be compatible with local renderPass
615711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                skipCall |=
615811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
615911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
616011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            reinterpret_cast<uint64_t>(commandBuffer), __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE,
616111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            "DS", "vkBeginCommandBuffer(): Secondary Command "
616211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                  "Buffer (0x%p) renderPass (0x%" PRIxLEAST64 ") is incompatible w/ framebuffer "
616311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                  "(0x%" PRIxLEAST64 ") w/ render pass (0x%" PRIxLEAST64 ") due to: %s",
616411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            reinterpret_cast<void *>(commandBuffer), (uint64_t)(pInfo->renderPass),
616511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            (uint64_t)(pInfo->framebuffer), (uint64_t)(fbRP), errorString.c_str());
616611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            }
616711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            // Connect this framebuffer to this cmdBuffer
616811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            framebuffer->referencingCmdBuffers.insert(pCB->commandBuffer);
616911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        }
617011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    }
617111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
617211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if ((pInfo->occlusionQueryEnable == VK_FALSE ||
617311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                     dev_data->phys_dev_properties.features.occlusionQueryPrecise == VK_FALSE) &&
617411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    (pInfo->queryFlags & VK_QUERY_CONTROL_PRECISE_BIT)) {
617511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
617611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t>(commandBuffer),
617711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS",
617811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        "vkBeginCommandBuffer(): Secondary Command Buffer (0x%p) must not have "
617911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        "VK_QUERY_CONTROL_PRECISE_BIT if occulusionQuery is disabled or the device does not "
618011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        "support precise occlusion queries.",
618111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        reinterpret_cast<void *>(commandBuffer));
618211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
618311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
618411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (pInfo && pInfo->renderPass != VK_NULL_HANDLE) {
618511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                auto renderPass = getRenderPass(dev_data, pInfo->renderPass);
618611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (renderPass) {
618711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    if (pInfo->subpass >= renderPass->pCreateInfo->subpassCount) {
618811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
618911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)commandBuffer, __LINE__,
619011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS",
619111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            "vkBeginCommandBuffer(): Secondary Command Buffers (0x%p) must has a subpass index (%d) "
619211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            "that is less than the number of subpasses (%d).",
619311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            (void *)commandBuffer, pInfo->subpass, renderPass->pCreateInfo->subpassCount);
619411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    }
619511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
619611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
619711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
619811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (CB_RECORDING == pCB->state) {
619911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |=
620011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
620111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        (uint64_t)commandBuffer, __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS",
620211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "vkBeginCommandBuffer(): Cannot call Begin on CB (0x%" PRIxLEAST64
620311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        ") in the RECORDING state. Must first call vkEndCommandBuffer().",
620411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        (uint64_t)commandBuffer);
620511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else if (CB_RECORDED == pCB->state || (CB_INVALID == pCB->state && CMD_END == pCB->cmds.back().type)) {
620611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            VkCommandPool cmdPool = pCB->createInfo.commandPool;
620711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (!(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT & dev_data->commandPoolMap[cmdPool].createFlags)) {
620811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skipCall |=
620911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
621011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            (uint64_t)commandBuffer, __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER_RESET, "DS",
621111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "Call to vkBeginCommandBuffer() on command buffer (0x%" PRIxLEAST64
621211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            ") attempts to implicitly reset cmdBuffer created from command pool (0x%" PRIxLEAST64
621311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            ") that does NOT have the VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT bit set.",
621411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            (uint64_t)commandBuffer, (uint64_t)cmdPool);
621511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
621611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            resetCB(dev_data, commandBuffer);
621711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
621811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Set updated state here in case implicit reset occurs above
621911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->state = CB_RECORDING;
622011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->beginInfo = *pBeginInfo;
622111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (pCB->beginInfo.pInheritanceInfo) {
622211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pCB->inheritanceInfo = *(pCB->beginInfo.pInheritanceInfo);
622311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pCB->beginInfo.pInheritanceInfo = &pCB->inheritanceInfo;
622411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // If we are a secondary command-buffer and inheriting.  Update the items we should inherit.
622511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if ((pCB->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) &&
622611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                (pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
622711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pCB->activeRenderPass = getRenderPass(dev_data, pCB->beginInfo.pInheritanceInfo->renderPass);
622811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pCB->activeSubpass = pCB->beginInfo.pInheritanceInfo->subpass;
622911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pCB->framebuffers.insert(pCB->beginInfo.pInheritanceInfo->framebuffer);
623011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
623111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
623211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else {
623311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
623411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            (uint64_t)commandBuffer, __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
623511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "In vkBeginCommandBuffer() and unable to find CommandBuffer Node for CB 0x%p!", (void *)commandBuffer);
623611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
623711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
623811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (skipCall) {
623911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return VK_ERROR_VALIDATION_FAILED_EXT;
624011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
624111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = dev_data->device_dispatch_table->BeginCommandBuffer(commandBuffer, pBeginInfo);
624211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
624311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
624411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
624511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
624611cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL EndCommandBuffer(VkCommandBuffer commandBuffer) {
624711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
624811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = VK_SUCCESS;
624911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
625011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
625111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
625211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
625311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if ((VK_COMMAND_BUFFER_LEVEL_PRIMARY == pCB->createInfo.level) || !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
625411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // This needs spec clarification to update valid usage, see comments in PR:
625511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/pull/516#discussion_r63013756
625611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= insideRenderPass(dev_data, pCB, "vkEndCommandBuffer");
625711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
625811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= addCmd(dev_data, pCB, CMD_END, "vkEndCommandBuffer()");
625911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (auto query : pCB->activeQueries) {
626011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
626111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                DRAWSTATE_INVALID_QUERY, "DS",
626211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                "Ending command buffer with in progress query: queryPool 0x%" PRIx64 ", index %d",
626311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                (uint64_t)(query.pool), query.index);
626411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
626511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
626611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall) {
626711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        lock.unlock();
626811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        result = dev_data->device_dispatch_table->EndCommandBuffer(commandBuffer);
626911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        lock.lock();
627011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (VK_SUCCESS == result) {
627111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pCB->state = CB_RECORDED;
627211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // Reset CB status flags
627311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pCB->status = 0;
627411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            printCB(dev_data, commandBuffer);
627511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
627611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else {
627711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        result = VK_ERROR_VALIDATION_FAILED_EXT;
627811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
627911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
628011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
628111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
628211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
628311cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL
628411cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertResetCommandBuffer(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags) {
628511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
628611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
628711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
628811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
628911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkCommandPool cmdPool = pCB->createInfo.commandPool;
629011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT & dev_data->commandPoolMap[cmdPool].createFlags)) {
629111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
629211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             (uint64_t)commandBuffer, __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER_RESET, "DS",
629311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             "Attempt to reset command buffer (0x%" PRIxLEAST64 ") created from command pool (0x%" PRIxLEAST64
629411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             ") that does NOT have the VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT bit set.",
629511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             (uint64_t)commandBuffer, (uint64_t)cmdPool);
629611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
629711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skip_call |= checkAndClearCommandBufferInFlight(dev_data, pCB, "reset");
629811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
629911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (skip_call)
630011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return VK_ERROR_VALIDATION_FAILED_EXT;
630111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = dev_data->device_dispatch_table->ResetCommandBuffer(commandBuffer, flags);
630211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (VK_SUCCESS == result) {
630311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        lock.lock();
630411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        resetCB(dev_data, commandBuffer);
630511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        lock.unlock();
630611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
630711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
630811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
630911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
631011cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
631111cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCmdBindPipeline(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline) {
631211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
631311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
631411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
631511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
631611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
631711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= addCmd(dev_data, pCB, CMD_BINDPIPELINE, "vkCmdBindPipeline()");
631811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if ((VK_PIPELINE_BIND_POINT_COMPUTE == pipelineBindPoint) && (pCB->activeRenderPass)) {
631911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |=
632011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
632111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        (uint64_t)pipeline, __LINE__, DRAWSTATE_INVALID_RENDERPASS_CMD, "DS",
632211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "Incorrectly binding compute pipeline (0x%" PRIxLEAST64 ") during active RenderPass (0x%" PRIxLEAST64 ")",
632311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        (uint64_t)pipeline, (uint64_t)pCB->activeRenderPass->renderPass);
632411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
632511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
632611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        PIPELINE_NODE *pPN = getPipeline(dev_data, pipeline);
632711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (pPN) {
632811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pCB->lastBound[pipelineBindPoint].pipeline = pipeline;
632911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            set_cb_pso_status(pCB, pPN);
633011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            set_pipeline_state(pPN);
633111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
633211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
633311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                (uint64_t)pipeline, __LINE__, DRAWSTATE_INVALID_PIPELINE, "DS",
633411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                "Attempt to bind Pipeline 0x%" PRIxLEAST64 " that doesn't exist!", (uint64_t)(pipeline));
633511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
633611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
633711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
633811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
633911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdBindPipeline(commandBuffer, pipelineBindPoint, pipeline);
634011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
634111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
634211cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
634311cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCmdSetViewport(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport *pViewports) {
634411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
634511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
634611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
634711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
634811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
634911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= addCmd(dev_data, pCB, CMD_SETVIEWPORTSTATE, "vkCmdSetViewport()");
635011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->status |= CBSTATUS_VIEWPORT_SET;
635111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->viewports.resize(viewportCount);
635211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        memcpy(pCB->viewports.data(), pViewports, viewportCount * sizeof(VkViewport));
635311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
635411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
635511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
635611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdSetViewport(commandBuffer, firstViewport, viewportCount, pViewports);
635711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
635811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
635911cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
636011cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCmdSetScissor(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount, const VkRect2D *pScissors) {
636111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
636211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
636311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
636411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
636511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
636611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= addCmd(dev_data, pCB, CMD_SETSCISSORSTATE, "vkCmdSetScissor()");
636711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->status |= CBSTATUS_SCISSOR_SET;
636811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->scissors.resize(scissorCount);
636911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        memcpy(pCB->scissors.data(), pScissors, scissorCount * sizeof(VkRect2D));
637011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
637111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
637211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
637311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdSetScissor(commandBuffer, firstScissor, scissorCount, pScissors);
637411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
637511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
637611cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL CmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth) {
637711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
637811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
637911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
638011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
638111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
638211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= addCmd(dev_data, pCB, CMD_SETLINEWIDTHSTATE, "vkCmdSetLineWidth()");
638311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->status |= CBSTATUS_LINE_WIDTH_SET;
638411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
638511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        PIPELINE_NODE *pPipeTrav = getPipeline(dev_data, pCB->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].pipeline);
638611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (pPipeTrav != NULL && !isDynamic(pPipeTrav, VK_DYNAMIC_STATE_LINE_WIDTH)) {
638711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0,
638811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 reinterpret_cast<uint64_t &>(commandBuffer), __LINE__, DRAWSTATE_INVALID_SET, "DS",
638911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 "vkCmdSetLineWidth called but pipeline was created without VK_DYNAMIC_STATE_LINE_WIDTH "
639011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 "flag.  This is undefined behavior and could be ignored.");
639111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
639211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |= verifyLineWidth(dev_data, DRAWSTATE_INVALID_SET, reinterpret_cast<uint64_t &>(commandBuffer), lineWidth);
639311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
639411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
639511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
639611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skip_call)
639711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdSetLineWidth(commandBuffer, lineWidth);
639811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
639911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
640011cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
640111cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCmdSetDepthBias(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor) {
640211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
640311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
640411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
640511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
640611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
640711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= addCmd(dev_data, pCB, CMD_SETDEPTHBIASSTATE, "vkCmdSetDepthBias()");
640811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->status |= CBSTATUS_DEPTH_BIAS_SET;
640911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
641011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
641111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
641211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdSetDepthBias(commandBuffer, depthBiasConstantFactor, depthBiasClamp,
641311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                         depthBiasSlopeFactor);
641411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
641511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
641611cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL CmdSetBlendConstants(VkCommandBuffer commandBuffer, const float blendConstants[4]) {
641711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
641811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
641911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
642011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
642111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
642211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= addCmd(dev_data, pCB, CMD_SETBLENDSTATE, "vkCmdSetBlendConstants()");
642311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->status |= CBSTATUS_BLEND_CONSTANTS_SET;
642411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
642511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
642611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
642711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdSetBlendConstants(commandBuffer, blendConstants);
642811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
642911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
643011cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
643111cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCmdSetDepthBounds(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds) {
643211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
643311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
643411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
643511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
643611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
643711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= addCmd(dev_data, pCB, CMD_SETDEPTHBOUNDSSTATE, "vkCmdSetDepthBounds()");
643811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->status |= CBSTATUS_DEPTH_BOUNDS_SET;
643911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
644011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
644111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
644211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdSetDepthBounds(commandBuffer, minDepthBounds, maxDepthBounds);
644311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
644411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
644511cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
644611cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCmdSetStencilCompareMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t compareMask) {
644711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
644811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
644911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
645011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
645111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
645211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= addCmd(dev_data, pCB, CMD_SETSTENCILREADMASKSTATE, "vkCmdSetStencilCompareMask()");
645311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->status |= CBSTATUS_STENCIL_READ_MASK_SET;
645411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
645511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
645611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
645711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdSetStencilCompareMask(commandBuffer, faceMask, compareMask);
645811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
645911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
646011cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
646111cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCmdSetStencilWriteMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask) {
646211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
646311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
646411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
646511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
646611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
646711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= addCmd(dev_data, pCB, CMD_SETSTENCILWRITEMASKSTATE, "vkCmdSetStencilWriteMask()");
646811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->status |= CBSTATUS_STENCIL_WRITE_MASK_SET;
646911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
647011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
647111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
647211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdSetStencilWriteMask(commandBuffer, faceMask, writeMask);
647311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
647411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
647511cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
647611cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCmdSetStencilReference(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference) {
647711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
647811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
647911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
648011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
648111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
648211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= addCmd(dev_data, pCB, CMD_SETSTENCILREFERENCESTATE, "vkCmdSetStencilReference()");
648311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->status |= CBSTATUS_STENCIL_REFERENCE_SET;
648411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
648511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
648611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
648711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdSetStencilReference(commandBuffer, faceMask, reference);
648811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
648911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
649011cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
649111cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCmdBindDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout,
649211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                      uint32_t firstSet, uint32_t setCount, const VkDescriptorSet *pDescriptorSets, uint32_t dynamicOffsetCount,
649311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                      const uint32_t *pDynamicOffsets) {
649411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
649511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
649611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
649711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
649811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
649911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (pCB->state == CB_RECORDING) {
650011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // Track total count of dynamic descriptor types to make sure we have an offset for each one
650111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            uint32_t totalDynamicDescriptors = 0;
650211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            string errorString = "";
650311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            uint32_t lastSetIndex = firstSet + setCount - 1;
650411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (lastSetIndex >= pCB->lastBound[pipelineBindPoint].boundDescriptorSets.size()) {
650511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pCB->lastBound[pipelineBindPoint].boundDescriptorSets.resize(lastSetIndex + 1);
650611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pCB->lastBound[pipelineBindPoint].dynamicOffsets.resize(lastSetIndex + 1);
650711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
650811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            auto oldFinalBoundSet = pCB->lastBound[pipelineBindPoint].boundDescriptorSets[lastSetIndex];
650911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (uint32_t i = 0; i < setCount; i++) {
651011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                cvdescriptorset::DescriptorSet *pSet = getSetNode(dev_data, pDescriptorSets[i]);
651111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (pSet) {
651211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    pCB->lastBound[pipelineBindPoint].uniqueBoundSets.insert(pSet);
651311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    pSet->BindCommandBuffer(pCB);
651411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    pCB->lastBound[pipelineBindPoint].pipelineLayout = layout;
651511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    pCB->lastBound[pipelineBindPoint].boundDescriptorSets[i + firstSet] = pSet;
651611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT,
651711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i], __LINE__,
651811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        DRAWSTATE_NONE, "DS", "DS 0x%" PRIxLEAST64 " bound on pipeline %s",
651911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        (uint64_t)pDescriptorSets[i], string_VkPipelineBindPoint(pipelineBindPoint));
652011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    if (!pSet->IsUpdated() && (pSet->GetTotalDescriptorCount() != 0)) {
652111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
652211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i],
652311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS",
652411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            "DS 0x%" PRIxLEAST64
652511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            " bound but it was never updated. You may want to either update it or not bind it.",
652611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            (uint64_t)pDescriptorSets[i]);
652711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    }
652811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    // Verify that set being bound is compatible with overlapping setLayout of pipelineLayout
652911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    if (!verify_set_layout_compatibility(dev_data, pSet, layout, i + firstSet, errorString)) {
653011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
653111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i], __LINE__,
653211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            DRAWSTATE_PIPELINE_LAYOUTS_INCOMPATIBLE, "DS",
653311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            "descriptorSet #%u being bound is not compatible with overlapping descriptorSetLayout "
653411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            "at index %u of pipelineLayout 0x%" PRIxLEAST64 " due to: %s",
653511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            i, i + firstSet, reinterpret_cast<uint64_t &>(layout), errorString.c_str());
653611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    }
653711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
653811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    auto setDynamicDescriptorCount = pSet->GetDynamicDescriptorCount();
653911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
654011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    pCB->lastBound[pipelineBindPoint].dynamicOffsets[firstSet + i].clear();
654111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
654211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    if (setDynamicDescriptorCount) {
654311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        // First make sure we won't overstep bounds of pDynamicOffsets array
654411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        if ((totalDynamicDescriptors + setDynamicDescriptorCount) > dynamicOffsetCount) {
654511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            skipCall |=
654611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
654711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i], __LINE__,
654811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        DRAWSTATE_INVALID_DYNAMIC_OFFSET_COUNT, "DS",
654911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        "descriptorSet #%u (0x%" PRIxLEAST64
655011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        ") requires %u dynamicOffsets, but only %u dynamicOffsets are left in pDynamicOffsets "
655111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        "array. There must be one dynamic offset for each dynamic descriptor being bound.",
655211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        i, (uint64_t)pDescriptorSets[i], pSet->GetDynamicDescriptorCount(),
655311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        (dynamicOffsetCount - totalDynamicDescriptors));
655411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        } else { // Validate and store dynamic offsets with the set
655511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            // Validate Dynamic Offset Minimums
655611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            uint32_t cur_dyn_offset = totalDynamicDescriptors;
655711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            for (uint32_t d = 0; d < pSet->GetTotalDescriptorCount(); d++) {
655811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                if (pSet->GetTypeFromGlobalIndex(d) == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) {
655911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    if (vk_safe_modulo(
656011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            pDynamicOffsets[cur_dyn_offset],
656111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment) != 0) {
656211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        skipCall |= log_msg(
656311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
656411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__,
656511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            DRAWSTATE_INVALID_UNIFORM_BUFFER_OFFSET, "DS",
656611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            "vkCmdBindDescriptorSets(): pDynamicOffsets[%d] is %d but must be a multiple of "
656711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            "device limit minUniformBufferOffsetAlignment 0x%" PRIxLEAST64,
656811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            cur_dyn_offset, pDynamicOffsets[cur_dyn_offset],
656911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment);
657011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    }
657111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    cur_dyn_offset++;
657211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                } else if (pSet->GetTypeFromGlobalIndex(d) == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
657311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    if (vk_safe_modulo(
657411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            pDynamicOffsets[cur_dyn_offset],
657511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            dev_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment) != 0) {
657611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        skipCall |= log_msg(
657711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
657811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__,
657911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            DRAWSTATE_INVALID_STORAGE_BUFFER_OFFSET, "DS",
658011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            "vkCmdBindDescriptorSets(): pDynamicOffsets[%d] is %d but must be a multiple of "
658111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            "device limit minStorageBufferOffsetAlignment 0x%" PRIxLEAST64,
658211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            cur_dyn_offset, pDynamicOffsets[cur_dyn_offset],
658311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            dev_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment);
658411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    }
658511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    cur_dyn_offset++;
658611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                }
658711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            }
658811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
658911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            pCB->lastBound[pipelineBindPoint].dynamicOffsets[firstSet + i] =
659011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                std::vector<uint32_t>(pDynamicOffsets + totalDynamicDescriptors,
659111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                      pDynamicOffsets + totalDynamicDescriptors + setDynamicDescriptorCount);
659211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            // Keep running total of dynamic descriptor count to verify at the end
659311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            totalDynamicDescriptors += setDynamicDescriptorCount;
659411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
659511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        }
659611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    }
659711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                } else {
659811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
659911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i], __LINE__,
660011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        DRAWSTATE_INVALID_SET, "DS", "Attempt to bind DS 0x%" PRIxLEAST64 " that doesn't exist!",
660111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        (uint64_t)pDescriptorSets[i]);
660211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
660311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skipCall |= addCmd(dev_data, pCB, CMD_BINDDESCRIPTORSETS, "vkCmdBindDescriptorSets()");
660411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                // For any previously bound sets, need to set them to "invalid" if they were disturbed by this update
660511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (firstSet > 0) { // Check set #s below the first bound set
660611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    for (uint32_t i = 0; i < firstSet; ++i) {
660711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        if (pCB->lastBound[pipelineBindPoint].boundDescriptorSets[i] &&
660811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            !verify_set_layout_compatibility(dev_data, pCB->lastBound[pipelineBindPoint].boundDescriptorSets[i],
660911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                             layout, i, errorString)) {
661011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            skipCall |= log_msg(
661111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
661211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
661311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                (uint64_t)pCB->lastBound[pipelineBindPoint].boundDescriptorSets[i], __LINE__, DRAWSTATE_NONE, "DS",
661411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                "DescriptorSetDS 0x%" PRIxLEAST64
661511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                " previously bound as set #%u was disturbed by newly bound pipelineLayout (0x%" PRIxLEAST64 ")",
661611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                (uint64_t)pCB->lastBound[pipelineBindPoint].boundDescriptorSets[i], i, (uint64_t)layout);
661711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            pCB->lastBound[pipelineBindPoint].boundDescriptorSets[i] = VK_NULL_HANDLE;
661811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        }
661911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    }
662011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
662111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                // Check if newly last bound set invalidates any remaining bound sets
662211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if ((pCB->lastBound[pipelineBindPoint].boundDescriptorSets.size() - 1) > (lastSetIndex)) {
662311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    if (oldFinalBoundSet &&
662411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        !verify_set_layout_compatibility(dev_data, oldFinalBoundSet, layout, lastSetIndex, errorString)) {
662511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        auto old_set = oldFinalBoundSet->GetSet();
662611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        skipCall |=
662711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
662811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, reinterpret_cast<uint64_t &>(old_set), __LINE__,
662911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    DRAWSTATE_NONE, "DS", "DescriptorSetDS 0x%" PRIxLEAST64
663011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                          " previously bound as set #%u is incompatible with set 0x%" PRIxLEAST64
663111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                          " newly bound as set #%u so set #%u and any subsequent sets were "
663211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                          "disturbed by newly bound pipelineLayout (0x%" PRIxLEAST64 ")",
663311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    reinterpret_cast<uint64_t &>(old_set), lastSetIndex,
663411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    (uint64_t)pCB->lastBound[pipelineBindPoint].boundDescriptorSets[lastSetIndex], lastSetIndex,
663511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    lastSetIndex + 1, (uint64_t)layout);
663611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        pCB->lastBound[pipelineBindPoint].boundDescriptorSets.resize(lastSetIndex + 1);
663711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    }
663811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
663911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
664011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            //  dynamicOffsetCount must equal the total number of dynamic descriptors in the sets being bound
664111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (totalDynamicDescriptors != dynamicOffsetCount) {
664211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
664311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)commandBuffer, __LINE__,
664411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    DRAWSTATE_INVALID_DYNAMIC_OFFSET_COUNT, "DS",
664511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    "Attempting to bind %u descriptorSets with %u dynamic descriptors, but dynamicOffsetCount "
664611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    "is %u. It should exactly match the number of dynamic descriptors.",
664711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    setCount, totalDynamicDescriptors, dynamicOffsetCount);
664811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
664911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
665011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdBindDescriptorSets()");
665111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
665211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
665311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
665411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
665511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdBindDescriptorSets(commandBuffer, pipelineBindPoint, layout, firstSet, setCount,
665611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                               pDescriptorSets, dynamicOffsetCount, pDynamicOffsets);
665711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
665811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
665911cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
666011cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCmdBindIndexBuffer(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType) {
666111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
666211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
666311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODO : Somewhere need to verify that IBs have correct usage state flagged
666411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
666511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkDeviceMemory mem;
666611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall =
666711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        get_mem_binding_from_object(dev_data, (uint64_t)buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
666811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
666911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (cb_data != dev_data->commandBufferMap.end()) {
667011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::function<bool()> function = [=]() { return validate_memory_is_valid(dev_data, mem, "vkCmdBindIndexBuffer()"); };
667111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        cb_data->second->validate_functions.push_back(function);
667211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= addCmd(dev_data, cb_data->second, CMD_BINDINDEXBUFFER, "vkCmdBindIndexBuffer()");
667311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        VkDeviceSize offset_align = 0;
667411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        switch (indexType) {
667511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case VK_INDEX_TYPE_UINT16:
667611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            offset_align = 2;
667711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            break;
667811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        case VK_INDEX_TYPE_UINT32:
667911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            offset_align = 4;
668011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            break;
668111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        default:
668211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // ParamChecker should catch bad enum, we'll also throw alignment error below if offset_align stays 0
668311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            break;
668411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
668511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!offset_align || (offset % offset_align)) {
668611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
668711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                DRAWSTATE_VTX_INDEX_ALIGNMENT_ERROR, "DS",
668811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                "vkCmdBindIndexBuffer() offset (0x%" PRIxLEAST64 ") does not fall on alignment (%s) boundary.",
668911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                offset, string_VkIndexType(indexType));
669011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
669111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        cb_data->second->status |= CBSTATUS_INDEX_BUFFER_BOUND;
669211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
669311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
669411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
669511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdBindIndexBuffer(commandBuffer, buffer, offset, indexType);
669611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
669711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
669811cd02dfb91661c65134cac258cf5924270e9d2Dan Albertvoid updateResourceTracking(GLOBAL_CB_NODE *pCB, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer *pBuffers) {
669911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    uint32_t end = firstBinding + bindingCount;
670011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB->currentDrawData.buffers.size() < end) {
670111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->currentDrawData.buffers.resize(end);
670211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
670311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < bindingCount; ++i) {
670411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->currentDrawData.buffers[i + firstBinding] = pBuffers[i];
670511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
670611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
670711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
670811cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic inline void updateResourceTrackingOnDraw(GLOBAL_CB_NODE *pCB) { pCB->drawData.push_back(pCB->currentDrawData); }
670911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
671011cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL CmdBindVertexBuffers(VkCommandBuffer commandBuffer, uint32_t firstBinding,
671111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                uint32_t bindingCount, const VkBuffer *pBuffers,
671211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                const VkDeviceSize *pOffsets) {
671311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
671411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
671511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODO : Somewhere need to verify that VBs have correct usage state flagged
671611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
671711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
671811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (cb_data != dev_data->commandBufferMap.end()) {
671911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t i = 0; i < bindingCount; ++i) {
672011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            VkDeviceMemory mem;
672111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= get_mem_binding_from_object(dev_data, (uint64_t)pBuffers[i], VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
672211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
672311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            std::function<bool()> function = [=]() { return validate_memory_is_valid(dev_data, mem, "vkCmdBindVertexBuffers()"); };
672411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            cb_data->second->validate_functions.push_back(function);
672511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
672611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        addCmd(dev_data, cb_data->second, CMD_BINDVERTEXBUFFER, "vkCmdBindVertexBuffer()");
672711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        updateResourceTracking(cb_data->second, firstBinding, bindingCount, pBuffers);
672811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else {
672911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdBindVertexBuffer()");
673011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
673111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
673211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
673311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdBindVertexBuffers(commandBuffer, firstBinding, bindingCount, pBuffers, pOffsets);
673411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
673511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
673611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert/* expects global_lock to be held by caller */
673711cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool markStoreImagesAndBuffersAsWritten(layer_data *dev_data, GLOBAL_CB_NODE *pCB) {
673811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
673911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
674011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto imageView : pCB->updateImages) {
674111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto iv_data = dev_data->imageViewMap.find(imageView);
674211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (iv_data == dev_data->imageViewMap.end())
674311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            continue;
674411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        VkImage image = iv_data->second.image;
674511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        VkDeviceMemory mem;
674611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |=
674711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            get_mem_binding_from_object(dev_data, (uint64_t)image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
674811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::function<bool()> function = [=]() {
674911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            set_memory_valid(dev_data, mem, true, image);
675011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return false;
675111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        };
675211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->validate_functions.push_back(function);
675311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
675411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto buffer : pCB->updateBuffers) {
675511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        VkDeviceMemory mem;
675611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= get_mem_binding_from_object(dev_data, (uint64_t)buffer,
675711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                 VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
675811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::function<bool()> function = [=]() {
675911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            set_memory_valid(dev_data, mem, true);
676011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return false;
676111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        };
676211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->validate_functions.push_back(function);
676311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
676411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skip_call;
676511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
676611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
676711cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL CmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount,
676811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                   uint32_t firstVertex, uint32_t firstInstance) {
676911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
677011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
677111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
677211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
677311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
677411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= addCmd(dev_data, pCB, CMD_DRAW, "vkCmdDraw()");
677511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->drawCount[DRAW]++;
677611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= validate_and_update_draw_state(dev_data, pCB, false, VK_PIPELINE_BIND_POINT_GRAPHICS);
677711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= markStoreImagesAndBuffersAsWritten(dev_data, pCB);
677811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // TODO : Need to pass commandBuffer as srcObj here
677911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |=
678011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
678111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    __LINE__, DRAWSTATE_NONE, "DS", "vkCmdDraw() call 0x%" PRIx64 ", reporting DS state:", g_drawCount[DRAW]++);
678211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= synchAndPrintDSConfig(dev_data, commandBuffer);
678311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!skipCall) {
678411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            updateResourceTrackingOnDraw(pCB);
678511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
678611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdDraw");
678711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
678811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
678911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
679011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdDraw(commandBuffer, vertexCount, instanceCount, firstVertex, firstInstance);
679111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
679211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
679311cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL CmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount,
679411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                          uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset,
679511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                            uint32_t firstInstance) {
679611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
679711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
679811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
679911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
680011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
680111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= addCmd(dev_data, pCB, CMD_DRAWINDEXED, "vkCmdDrawIndexed()");
680211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->drawCount[DRAW_INDEXED]++;
680311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= validate_and_update_draw_state(dev_data, pCB, true, VK_PIPELINE_BIND_POINT_GRAPHICS);
680411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= markStoreImagesAndBuffersAsWritten(dev_data, pCB);
680511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // TODO : Need to pass commandBuffer as srcObj here
680611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT,
680711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, DRAWSTATE_NONE, "DS",
680811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "vkCmdDrawIndexed() call 0x%" PRIx64 ", reporting DS state:", g_drawCount[DRAW_INDEXED]++);
680911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= synchAndPrintDSConfig(dev_data, commandBuffer);
681011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!skipCall) {
681111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            updateResourceTrackingOnDraw(pCB);
681211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
681311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdDrawIndexed");
681411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
681511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
681611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
681711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdDrawIndexed(commandBuffer, indexCount, instanceCount, firstIndex, vertexOffset,
681811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                        firstInstance);
681911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
682011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
682111cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
682211cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count, uint32_t stride) {
682311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
682411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
682511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
682611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkDeviceMemory mem;
682711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // MTMTODO : merge with code below
682811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall =
682911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        get_mem_binding_from_object(dev_data, (uint64_t)buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
683011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdDrawIndirect");
683111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
683211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
683311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= addCmd(dev_data, pCB, CMD_DRAWINDIRECT, "vkCmdDrawIndirect()");
683411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->drawCount[DRAW_INDIRECT]++;
683511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= validate_and_update_draw_state(dev_data, pCB, false, VK_PIPELINE_BIND_POINT_GRAPHICS);
683611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= markStoreImagesAndBuffersAsWritten(dev_data, pCB);
683711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // TODO : Need to pass commandBuffer as srcObj here
683811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT,
683911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, DRAWSTATE_NONE, "DS",
684011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "vkCmdDrawIndirect() call 0x%" PRIx64 ", reporting DS state:", g_drawCount[DRAW_INDIRECT]++);
684111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= synchAndPrintDSConfig(dev_data, commandBuffer);
684211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!skipCall) {
684311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            updateResourceTrackingOnDraw(pCB);
684411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
684511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdDrawIndirect");
684611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
684711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
684811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
684911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdDrawIndirect(commandBuffer, buffer, offset, count, stride);
685011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
685111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
685211cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
685311cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count, uint32_t stride) {
685411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
685511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
685611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
685711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkDeviceMemory mem;
685811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // MTMTODO : merge with code below
685911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall =
686011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        get_mem_binding_from_object(dev_data, (uint64_t)buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
686111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdDrawIndexedIndirect");
686211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
686311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
686411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= addCmd(dev_data, pCB, CMD_DRAWINDEXEDINDIRECT, "vkCmdDrawIndexedIndirect()");
686511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->drawCount[DRAW_INDEXED_INDIRECT]++;
686611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= validate_and_update_draw_state(dev_data, pCB, true, VK_PIPELINE_BIND_POINT_GRAPHICS);
686711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= markStoreImagesAndBuffersAsWritten(dev_data, pCB);
686811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // TODO : Need to pass commandBuffer as srcObj here
686911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |=
687011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
687111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    __LINE__, DRAWSTATE_NONE, "DS", "vkCmdDrawIndexedIndirect() call 0x%" PRIx64 ", reporting DS state:",
687211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    g_drawCount[DRAW_INDEXED_INDIRECT]++);
687311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= synchAndPrintDSConfig(dev_data, commandBuffer);
687411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!skipCall) {
687511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            updateResourceTrackingOnDraw(pCB);
687611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
687711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdDrawIndexedIndirect");
687811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
687911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
688011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
688111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdDrawIndexedIndirect(commandBuffer, buffer, offset, count, stride);
688211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
688311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
688411cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL CmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z) {
688511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
688611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
688711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
688811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
688911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
689011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= validate_and_update_draw_state(dev_data, pCB, false, VK_PIPELINE_BIND_POINT_COMPUTE);
689111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // TODO : Call below is temporary until call above can be re-enabled
689211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        update_shader_storage_images_and_buffers(dev_data, pCB);
689311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= markStoreImagesAndBuffersAsWritten(dev_data, pCB);
689411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= addCmd(dev_data, pCB, CMD_DISPATCH, "vkCmdDispatch()");
689511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= insideRenderPass(dev_data, pCB, "vkCmdDispatch");
689611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
689711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
689811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
689911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdDispatch(commandBuffer, x, y, z);
690011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
690111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
690211cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
690311cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset) {
690411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
690511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
690611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
690711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkDeviceMemory mem;
690811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall =
690911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        get_mem_binding_from_object(dev_data, (uint64_t)buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
691011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdDispatchIndirect");
691111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
691211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
691311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= validate_and_update_draw_state(dev_data, pCB, false, VK_PIPELINE_BIND_POINT_COMPUTE);
691411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // TODO : Call below is temporary until call above can be re-enabled
691511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        update_shader_storage_images_and_buffers(dev_data, pCB);
691611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= markStoreImagesAndBuffersAsWritten(dev_data, pCB);
691711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= addCmd(dev_data, pCB, CMD_DISPATCHINDIRECT, "vkCmdDispatchIndirect()");
691811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= insideRenderPass(dev_data, pCB, "vkCmdDispatchIndirect");
691911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
692011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
692111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
692211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdDispatchIndirect(commandBuffer, buffer, offset);
692311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
692411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
692511cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL CmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
692611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         uint32_t regionCount, const VkBufferCopy *pRegions) {
692711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
692811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
692911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
693011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkDeviceMemory src_mem, dst_mem;
693111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall = get_mem_binding_from_object(dev_data, (uint64_t)srcBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &src_mem);
693211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, src_mem, "vkCmdCopyBuffer");
693311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= get_mem_binding_from_object(dev_data, (uint64_t)dstBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &dst_mem);
693411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
693511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, dst_mem, "vkCmdCopyBuffer");
693611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Validate that SRC & DST buffers have correct usage flags set
693711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= validate_buffer_usage_flags(dev_data, srcBuffer, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, true,
693811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            "vkCmdCopyBuffer()", "VK_BUFFER_USAGE_TRANSFER_SRC_BIT");
693911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= validate_buffer_usage_flags(dev_data, dstBuffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true,
694011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            "vkCmdCopyBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
694111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
694211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (cb_data != dev_data->commandBufferMap.end()) {
694311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::function<bool()> function = [=]() { return validate_memory_is_valid(dev_data, src_mem, "vkCmdCopyBuffer()"); };
694411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        cb_data->second->validate_functions.push_back(function);
694511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        function = [=]() {
694611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            set_memory_valid(dev_data, dst_mem, true);
694711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return false;
694811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        };
694911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        cb_data->second->validate_functions.push_back(function);
695011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
695111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= addCmd(dev_data, cb_data->second, CMD_COPYBUFFER, "vkCmdCopyBuffer()");
695211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= insideRenderPass(dev_data, cb_data->second, "vkCmdCopyBuffer");
695311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
695411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
695511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
695611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, regionCount, pRegions);
695711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
695811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
695911cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool VerifySourceImageLayout(VkCommandBuffer cmdBuffer, VkImage srcImage, VkImageSubresourceLayers subLayers,
696011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    VkImageLayout srcImageLayout) {
696111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
696211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
696311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map);
696411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer);
696511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < subLayers.layerCount; ++i) {
696611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        uint32_t layer = i + subLayers.baseArrayLayer;
696711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        VkImageSubresource sub = {subLayers.aspectMask, subLayers.mipLevel, layer};
696811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        IMAGE_CMD_BUF_LAYOUT_NODE node;
696911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!FindLayout(pCB, srcImage, sub, node)) {
697011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            SetLayout(pCB, srcImage, sub, IMAGE_CMD_BUF_LAYOUT_NODE(srcImageLayout, srcImageLayout));
697111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            continue;
697211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
697311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (node.layout != srcImageLayout) {
697411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // TODO: Improve log message in the next pass
697511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |=
697611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
697711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Cannot copy from an image whose source layout is %s "
697811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                        "and doesn't match the current layout %s.",
697911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        string_VkImageLayout(srcImageLayout), string_VkImageLayout(node.layout));
698011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
698111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
698211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (srcImageLayout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) {
698311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (srcImageLayout == VK_IMAGE_LAYOUT_GENERAL) {
698411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // LAYOUT_GENERAL is allowed, but may not be performance optimal, flag as perf warning.
698511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0,
698611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
698711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 "Layout for input image should be TRANSFER_SRC_OPTIMAL instead of GENERAL.");
698811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
698911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
699011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Layout for input image is %s but can only be "
699111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                       "TRANSFER_SRC_OPTIMAL or GENERAL.",
699211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 string_VkImageLayout(srcImageLayout));
699311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
699411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
699511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skip_call;
699611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
699711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
699811cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool VerifyDestImageLayout(VkCommandBuffer cmdBuffer, VkImage destImage, VkImageSubresourceLayers subLayers,
699911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                  VkImageLayout destImageLayout) {
700011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
700111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
700211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map);
700311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer);
700411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < subLayers.layerCount; ++i) {
700511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        uint32_t layer = i + subLayers.baseArrayLayer;
700611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        VkImageSubresource sub = {subLayers.aspectMask, subLayers.mipLevel, layer};
700711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        IMAGE_CMD_BUF_LAYOUT_NODE node;
700811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!FindLayout(pCB, destImage, sub, node)) {
700911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            SetLayout(pCB, destImage, sub, IMAGE_CMD_BUF_LAYOUT_NODE(destImageLayout, destImageLayout));
701011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            continue;
701111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
701211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (node.layout != destImageLayout) {
701311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |=
701411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
701511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Cannot copy from an image whose dest layout is %s and "
701611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                        "doesn't match the current layout %s.",
701711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        string_VkImageLayout(destImageLayout), string_VkImageLayout(node.layout));
701811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
701911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
702011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (destImageLayout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
702111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (destImageLayout == VK_IMAGE_LAYOUT_GENERAL) {
702211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // LAYOUT_GENERAL is allowed, but may not be performance optimal, flag as perf warning.
702311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0,
702411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
702511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 "Layout for output image should be TRANSFER_DST_OPTIMAL instead of GENERAL.");
702611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
702711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
702811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Layout for output image is %s but can only be "
702911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                       "TRANSFER_DST_OPTIMAL or GENERAL.",
703011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 string_VkImageLayout(destImageLayout));
703111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
703211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
703311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skip_call;
703411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
703511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
703611cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
703711cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage,
703811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert             VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy *pRegions) {
703911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
704011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
704111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
704211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkDeviceMemory src_mem, dst_mem;
704311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Validate that src & dst images have correct usage flags set
704411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall = get_mem_binding_from_object(dev_data, (uint64_t)srcImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &src_mem);
704511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, src_mem, "vkCmdCopyImage");
704611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
704711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= get_mem_binding_from_object(dev_data, (uint64_t)dstImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &dst_mem);
704811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, dst_mem, "vkCmdCopyImage");
704911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= validate_image_usage_flags(dev_data, srcImage, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true,
705011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                           "vkCmdCopyImage()", "VK_IMAGE_USAGE_TRANSFER_SRC_BIT");
705111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= validate_image_usage_flags(dev_data, dstImage, VK_IMAGE_USAGE_TRANSFER_DST_BIT, true,
705211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                           "vkCmdCopyImage()", "VK_IMAGE_USAGE_TRANSFER_DST_BIT");
705311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
705411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (cb_data != dev_data->commandBufferMap.end()) {
705511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::function<bool()> function = [=]() {
705611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return validate_memory_is_valid(dev_data, src_mem, "vkCmdCopyImage()", srcImage);
705711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        };
705811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        cb_data->second->validate_functions.push_back(function);
705911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        function = [=]() {
706011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            set_memory_valid(dev_data, dst_mem, true, dstImage);
706111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return false;
706211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        };
706311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        cb_data->second->validate_functions.push_back(function);
706411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
706511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= addCmd(dev_data, cb_data->second, CMD_COPYIMAGE, "vkCmdCopyImage()");
706611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= insideRenderPass(dev_data, cb_data->second, "vkCmdCopyImage");
706711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t i = 0; i < regionCount; ++i) {
706811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= VerifySourceImageLayout(commandBuffer, srcImage, pRegions[i].srcSubresource, srcImageLayout);
706911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= VerifyDestImageLayout(commandBuffer, dstImage, pRegions[i].dstSubresource, dstImageLayout);
707011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
707111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
707211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
707311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
707411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdCopyImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout,
707511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                      regionCount, pRegions);
707611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
707711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
707811cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
707911cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage,
708011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert             VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit *pRegions, VkFilter filter) {
708111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
708211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
708311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
708411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkDeviceMemory src_mem, dst_mem;
708511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Validate that src & dst images have correct usage flags set
708611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall = get_mem_binding_from_object(dev_data, (uint64_t)srcImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &src_mem);
708711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, src_mem, "vkCmdBlitImage");
708811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
708911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= get_mem_binding_from_object(dev_data, (uint64_t)dstImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &dst_mem);
709011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, dst_mem, "vkCmdBlitImage");
709111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= validate_image_usage_flags(dev_data, srcImage, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true,
709211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                           "vkCmdBlitImage()", "VK_IMAGE_USAGE_TRANSFER_SRC_BIT");
709311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= validate_image_usage_flags(dev_data, dstImage, VK_IMAGE_USAGE_TRANSFER_DST_BIT, true,
709411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                           "vkCmdBlitImage()", "VK_IMAGE_USAGE_TRANSFER_DST_BIT");
709511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
709611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
709711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (cb_data != dev_data->commandBufferMap.end()) {
709811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::function<bool()> function = [=]() {
709911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return validate_memory_is_valid(dev_data, src_mem, "vkCmdBlitImage()", srcImage);
710011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        };
710111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        cb_data->second->validate_functions.push_back(function);
710211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        function = [=]() {
710311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            set_memory_valid(dev_data, dst_mem, true, dstImage);
710411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return false;
710511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        };
710611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        cb_data->second->validate_functions.push_back(function);
710711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
710811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= addCmd(dev_data, cb_data->second, CMD_BLITIMAGE, "vkCmdBlitImage()");
710911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= insideRenderPass(dev_data, cb_data->second, "vkCmdBlitImage");
711011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
711111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
711211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
711311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdBlitImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout,
711411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                      regionCount, pRegions, filter);
711511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
711611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
711711cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL CmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer,
711811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                VkImage dstImage, VkImageLayout dstImageLayout,
711911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                uint32_t regionCount, const VkBufferImageCopy *pRegions) {
712011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
712111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
712211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
712311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkDeviceMemory dst_mem, src_mem;
712411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall = get_mem_binding_from_object(dev_data, (uint64_t)dstImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &dst_mem);
712511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, dst_mem, "vkCmdCopyBufferToImage");
712611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
712711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= get_mem_binding_from_object(dev_data, (uint64_t)srcBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &src_mem);
712811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, src_mem, "vkCmdCopyBufferToImage");
712911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Validate that src buff & dst image have correct usage flags set
713011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= validate_buffer_usage_flags(dev_data, srcBuffer, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, true, "vkCmdCopyBufferToImage()",
713111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            "VK_BUFFER_USAGE_TRANSFER_SRC_BIT");
713211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= validate_image_usage_flags(dev_data, dstImage, VK_IMAGE_USAGE_TRANSFER_DST_BIT, true, "vkCmdCopyBufferToImage()",
713311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                           "VK_IMAGE_USAGE_TRANSFER_DST_BIT");
713411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
713511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (cb_data != dev_data->commandBufferMap.end()) {
713611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::function<bool()> function = [=]() {
713711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            set_memory_valid(dev_data, dst_mem, true, dstImage);
713811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return false;
713911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        };
714011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        cb_data->second->validate_functions.push_back(function);
714111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        function = [=]() { return validate_memory_is_valid(dev_data, src_mem, "vkCmdCopyBufferToImage()"); };
714211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        cb_data->second->validate_functions.push_back(function);
714311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
714411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= addCmd(dev_data, cb_data->second, CMD_COPYBUFFERTOIMAGE, "vkCmdCopyBufferToImage()");
714511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= insideRenderPass(dev_data, cb_data->second, "vkCmdCopyBufferToImage");
714611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t i = 0; i < regionCount; ++i) {
714711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= VerifyDestImageLayout(commandBuffer, dstImage, pRegions[i].imageSubresource, dstImageLayout);
714811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
714911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
715011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
715111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
715211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdCopyBufferToImage(commandBuffer, srcBuffer, dstImage, dstImageLayout, regionCount,
715311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                              pRegions);
715411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
715511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
715611cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL CmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage,
715711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                VkImageLayout srcImageLayout, VkBuffer dstBuffer,
715811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                uint32_t regionCount, const VkBufferImageCopy *pRegions) {
715911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
716011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
716111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
716211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkDeviceMemory src_mem, dst_mem;
716311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall = get_mem_binding_from_object(dev_data, (uint64_t)srcImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &src_mem);
716411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, src_mem, "vkCmdCopyImageToBuffer");
716511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
716611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= get_mem_binding_from_object(dev_data, (uint64_t)dstBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &dst_mem);
716711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, dst_mem, "vkCmdCopyImageToBuffer");
716811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Validate that dst buff & src image have correct usage flags set
716911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= validate_image_usage_flags(dev_data, srcImage, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true, "vkCmdCopyImageToBuffer()",
717011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                           "VK_IMAGE_USAGE_TRANSFER_SRC_BIT");
717111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= validate_buffer_usage_flags(dev_data, dstBuffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, "vkCmdCopyImageToBuffer()",
717211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
717311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
717411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
717511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (cb_data != dev_data->commandBufferMap.end()) {
717611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::function<bool()> function = [=]() {
717711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return validate_memory_is_valid(dev_data, src_mem, "vkCmdCopyImageToBuffer()", srcImage);
717811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        };
717911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        cb_data->second->validate_functions.push_back(function);
718011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        function = [=]() {
718111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            set_memory_valid(dev_data, dst_mem, true);
718211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return false;
718311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        };
718411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        cb_data->second->validate_functions.push_back(function);
718511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
718611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= addCmd(dev_data, cb_data->second, CMD_COPYIMAGETOBUFFER, "vkCmdCopyImageToBuffer()");
718711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= insideRenderPass(dev_data, cb_data->second, "vkCmdCopyImageToBuffer");
718811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t i = 0; i < regionCount; ++i) {
718911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= VerifySourceImageLayout(commandBuffer, srcImage, pRegions[i].imageSubresource, srcImageLayout);
719011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
719111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
719211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
719311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
719411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdCopyImageToBuffer(commandBuffer, srcImage, srcImageLayout, dstBuffer, regionCount,
719511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                              pRegions);
719611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
719711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
719811cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL CmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer,
719911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                           VkDeviceSize dstOffset, VkDeviceSize dataSize, const uint32_t *pData) {
720011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
720111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
720211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
720311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkDeviceMemory mem;
720411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall =
720511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        get_mem_binding_from_object(dev_data, (uint64_t)dstBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
720611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdUpdateBuffer");
720711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Validate that dst buff has correct usage flags set
720811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= validate_buffer_usage_flags(dev_data, dstBuffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, "vkCmdUpdateBuffer()",
720911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
721011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
721111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
721211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (cb_data != dev_data->commandBufferMap.end()) {
721311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::function<bool()> function = [=]() {
721411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            set_memory_valid(dev_data, mem, true);
721511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return false;
721611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        };
721711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        cb_data->second->validate_functions.push_back(function);
721811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
721911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= addCmd(dev_data, cb_data->second, CMD_UPDATEBUFFER, "vkCmdUpdateBuffer()");
722011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= insideRenderPass(dev_data, cb_data->second, "vkCmdCopyUpdateBuffer");
722111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
722211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
722311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
722411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdUpdateBuffer(commandBuffer, dstBuffer, dstOffset, dataSize, pData);
722511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
722611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
722711cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
722811cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data) {
722911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
723011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
723111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
723211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkDeviceMemory mem;
723311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall =
723411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        get_mem_binding_from_object(dev_data, (uint64_t)dstBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
723511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdFillBuffer");
723611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Validate that dst buff has correct usage flags set
723711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= validate_buffer_usage_flags(dev_data, dstBuffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, "vkCmdFillBuffer()",
723811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
723911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
724011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
724111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (cb_data != dev_data->commandBufferMap.end()) {
724211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::function<bool()> function = [=]() {
724311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            set_memory_valid(dev_data, mem, true);
724411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return false;
724511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        };
724611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        cb_data->second->validate_functions.push_back(function);
724711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
724811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= addCmd(dev_data, cb_data->second, CMD_FILLBUFFER, "vkCmdFillBuffer()");
724911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= insideRenderPass(dev_data, cb_data->second, "vkCmdCopyFillBuffer");
725011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
725111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
725211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
725311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdFillBuffer(commandBuffer, dstBuffer, dstOffset, size, data);
725411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
725511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
725611cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL CmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount,
725711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                               const VkClearAttachment *pAttachments, uint32_t rectCount,
725811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                               const VkClearRect *pRects) {
725911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
726011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
726111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
726211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
726311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
726411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= addCmd(dev_data, pCB, CMD_CLEARATTACHMENTS, "vkCmdClearAttachments()");
726511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Warn if this is issued prior to Draw Cmd and clearing the entire attachment
726611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!hasDrawCmd(pCB) && (pCB->activeRenderPassBeginInfo.renderArea.extent.width == pRects[0].rect.extent.width) &&
726711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            (pCB->activeRenderPassBeginInfo.renderArea.extent.height == pRects[0].rect.extent.height)) {
726811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // TODO : commandBuffer should be srcObj
726911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // There are times where app needs to use ClearAttachments (generally when reusing a buffer inside of a render pass)
727011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // Can we make this warning more specific? I'd like to avoid triggering this test if we can tell it's a use that must
727111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // call CmdClearAttachments
727211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // Otherwise this seems more like a performance warning.
727311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
727411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, 0, DRAWSTATE_CLEAR_CMD_BEFORE_DRAW, "DS",
727511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                "vkCmdClearAttachments() issued on CB object 0x%" PRIxLEAST64 " prior to any Draw Cmds."
727611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                " It is recommended you use RenderPass LOAD_OP_CLEAR on Attachments prior to any Draw.",
727711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                (uint64_t)(commandBuffer));
727811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
727911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdClearAttachments");
728011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
728111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
728211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Validate that attachment is in reference list of active subpass
728311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB->activeRenderPass) {
728411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        const VkRenderPassCreateInfo *pRPCI = pCB->activeRenderPass->pCreateInfo;
728511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        const VkSubpassDescription *pSD = &pRPCI->pSubpasses[pCB->activeSubpass];
728611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
728711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t attachment_idx = 0; attachment_idx < attachmentCount; attachment_idx++) {
728811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            const VkClearAttachment *attachment = &pAttachments[attachment_idx];
728911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (attachment->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
729011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                bool found = false;
729111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                for (uint32_t i = 0; i < pSD->colorAttachmentCount; i++) {
729211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    if (attachment->colorAttachment == pSD->pColorAttachments[i].attachment) {
729311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        found = true;
729411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        break;
729511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    }
729611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
729711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (!found) {
729811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skipCall |= log_msg(
729911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
730011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        (uint64_t)commandBuffer, __LINE__, DRAWSTATE_MISSING_ATTACHMENT_REFERENCE, "DS",
730111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "vkCmdClearAttachments() attachment index %d not found in attachment reference array of active subpass %d",
730211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        attachment->colorAttachment, pCB->activeSubpass);
730311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
730411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            } else if (attachment->aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
730511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (!pSD->pDepthStencilAttachment || // Says no DS will be used in active subpass
730611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    (pSD->pDepthStencilAttachment->attachment ==
730711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                     VK_ATTACHMENT_UNUSED)) { // Says no DS will be used in active subpass
730811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
730911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skipCall |= log_msg(
731011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
731111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        (uint64_t)commandBuffer, __LINE__, DRAWSTATE_MISSING_ATTACHMENT_REFERENCE, "DS",
731211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "vkCmdClearAttachments() attachment index %d does not match depthStencilAttachment.attachment (%d) found "
731311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "in active subpass %d",
731411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        attachment->colorAttachment,
731511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        (pSD->pDepthStencilAttachment) ? pSD->pDepthStencilAttachment->attachment : VK_ATTACHMENT_UNUSED,
731611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        pCB->activeSubpass);
731711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
731811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
731911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
732011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
732111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
732211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
732311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdClearAttachments(commandBuffer, attachmentCount, pAttachments, rectCount, pRects);
732411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
732511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
732611cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL CmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image,
732711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                              VkImageLayout imageLayout, const VkClearColorValue *pColor,
732811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                              uint32_t rangeCount, const VkImageSubresourceRange *pRanges) {
732911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
733011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
733111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
733211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODO : Verify memory is in VK_IMAGE_STATE_CLEAR state
733311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkDeviceMemory mem;
733411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall = get_mem_binding_from_object(dev_data, (uint64_t)image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
733511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdClearColorImage");
733611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
733711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (cb_data != dev_data->commandBufferMap.end()) {
733811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::function<bool()> function = [=]() {
733911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            set_memory_valid(dev_data, mem, true, image);
734011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return false;
734111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        };
734211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        cb_data->second->validate_functions.push_back(function);
734311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
734411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= addCmd(dev_data, cb_data->second, CMD_CLEARCOLORIMAGE, "vkCmdClearColorImage()");
734511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= insideRenderPass(dev_data, cb_data->second, "vkCmdClearColorImage");
734611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
734711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
734811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
734911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdClearColorImage(commandBuffer, image, imageLayout, pColor, rangeCount, pRanges);
735011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
735111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
735211cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
735311cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
735411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                          const VkClearDepthStencilValue *pDepthStencil, uint32_t rangeCount,
735511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                          const VkImageSubresourceRange *pRanges) {
735611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
735711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
735811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
735911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODO : Verify memory is in VK_IMAGE_STATE_CLEAR state
736011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkDeviceMemory mem;
736111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall = get_mem_binding_from_object(dev_data, (uint64_t)image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
736211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdClearDepthStencilImage");
736311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
736411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (cb_data != dev_data->commandBufferMap.end()) {
736511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::function<bool()> function = [=]() {
736611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            set_memory_valid(dev_data, mem, true, image);
736711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return false;
736811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        };
736911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        cb_data->second->validate_functions.push_back(function);
737011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
737111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= addCmd(dev_data, cb_data->second, CMD_CLEARDEPTHSTENCILIMAGE, "vkCmdClearDepthStencilImage()");
737211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= insideRenderPass(dev_data, cb_data->second, "vkCmdClearDepthStencilImage");
737311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
737411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
737511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
737611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdClearDepthStencilImage(commandBuffer, image, imageLayout, pDepthStencil, rangeCount,
737711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                   pRanges);
737811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
737911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
738011cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
738111cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage,
738211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve *pRegions) {
738311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
738411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
738511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
738611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkDeviceMemory src_mem, dst_mem;
738711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall = get_mem_binding_from_object(dev_data, (uint64_t)srcImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &src_mem);
738811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, src_mem, "vkCmdResolveImage");
738911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
739011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= get_mem_binding_from_object(dev_data, (uint64_t)dstImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &dst_mem);
739111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, dst_mem, "vkCmdResolveImage");
739211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
739311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (cb_data != dev_data->commandBufferMap.end()) {
739411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::function<bool()> function = [=]() {
739511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return validate_memory_is_valid(dev_data, src_mem, "vkCmdResolveImage()", srcImage);
739611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        };
739711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        cb_data->second->validate_functions.push_back(function);
739811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        function = [=]() {
739911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            set_memory_valid(dev_data, dst_mem, true, dstImage);
740011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return false;
740111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        };
740211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        cb_data->second->validate_functions.push_back(function);
740311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
740411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= addCmd(dev_data, cb_data->second, CMD_RESOLVEIMAGE, "vkCmdResolveImage()");
740511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= insideRenderPass(dev_data, cb_data->second, "vkCmdResolveImage");
740611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
740711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
740811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
740911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdResolveImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout,
741011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                         regionCount, pRegions);
741111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
741211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
741311cd02dfb91661c65134cac258cf5924270e9d2Dan Albertbool setEventStageMask(VkQueue queue, VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
741411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
741511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
741611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
741711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->eventToStageMap[event] = stageMask;
741811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
741911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto queue_data = dev_data->queueMap.find(queue);
742011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (queue_data != dev_data->queueMap.end()) {
742111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        queue_data->second.eventToStageMap[event] = stageMask;
742211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
742311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return false;
742411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
742511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
742611cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
742711cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCmdSetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
742811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
742911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
743011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
743111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
743211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
743311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= addCmd(dev_data, pCB, CMD_SETEVENT, "vkCmdSetEvent()");
743411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= insideRenderPass(dev_data, pCB, "vkCmdSetEvent");
743511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->events.push_back(event);
743611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!pCB->waitedEvents.count(event)) {
743711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pCB->writeEventsBeforeWait.push_back(event);
743811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
743911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::function<bool(VkQueue)> eventUpdate =
744011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            std::bind(setEventStageMask, std::placeholders::_1, commandBuffer, event, stageMask);
744111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->eventUpdates.push_back(eventUpdate);
744211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
744311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
744411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
744511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdSetEvent(commandBuffer, event, stageMask);
744611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
744711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
744811cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
744911cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCmdResetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
745011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
745111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
745211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
745311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
745411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
745511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= addCmd(dev_data, pCB, CMD_RESETEVENT, "vkCmdResetEvent()");
745611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= insideRenderPass(dev_data, pCB, "vkCmdResetEvent");
745711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->events.push_back(event);
745811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!pCB->waitedEvents.count(event)) {
745911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pCB->writeEventsBeforeWait.push_back(event);
746011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
746111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::function<bool(VkQueue)> eventUpdate =
746211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            std::bind(setEventStageMask, std::placeholders::_1, commandBuffer, event, VkPipelineStageFlags(0));
746311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->eventUpdates.push_back(eventUpdate);
746411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
746511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
746611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
746711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdResetEvent(commandBuffer, event, stageMask);
746811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
746911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
747011cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool TransitionImageLayouts(VkCommandBuffer cmdBuffer, uint32_t memBarrierCount,
747111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                   const VkImageMemoryBarrier *pImgMemBarriers) {
747211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map);
747311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer);
747411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip = false;
747511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    uint32_t levelCount = 0;
747611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    uint32_t layerCount = 0;
747711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
747811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < memBarrierCount; ++i) {
747911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto mem_barrier = &pImgMemBarriers[i];
748011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!mem_barrier)
748111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            continue;
748211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // TODO: Do not iterate over every possibility - consolidate where
748311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // possible
748411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        ResolveRemainingLevelsLayers(dev_data, &levelCount, &layerCount, mem_barrier->subresourceRange, mem_barrier->image);
748511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
748611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t j = 0; j < levelCount; j++) {
748711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            uint32_t level = mem_barrier->subresourceRange.baseMipLevel + j;
748811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (uint32_t k = 0; k < layerCount; k++) {
748911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                uint32_t layer = mem_barrier->subresourceRange.baseArrayLayer + k;
749011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                VkImageSubresource sub = {mem_barrier->subresourceRange.aspectMask, level, layer};
749111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                IMAGE_CMD_BUF_LAYOUT_NODE node;
749211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (!FindLayout(pCB, mem_barrier->image, sub, node)) {
749311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    SetLayout(pCB, mem_barrier->image, sub,
749411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                              IMAGE_CMD_BUF_LAYOUT_NODE(mem_barrier->oldLayout, mem_barrier->newLayout));
749511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    continue;
749611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
749711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (mem_barrier->oldLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
749811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    // TODO: Set memory invalid which is in mem_tracker currently
749911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                } else if (node.layout != mem_barrier->oldLayout) {
750011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
750111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "You cannot transition the layout from %s "
750211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                                    "when current layout is %s.",
750311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    string_VkImageLayout(mem_barrier->oldLayout), string_VkImageLayout(node.layout));
750411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
750511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                SetLayout(pCB, mem_barrier->image, sub, mem_barrier->newLayout);
750611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
750711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
750811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
750911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skip;
751011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
751111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
751211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Print readable FlagBits in FlagMask
751311cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic std::string string_VkAccessFlags(VkAccessFlags accessMask) {
751411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::string result;
751511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::string separator;
751611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
751711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (accessMask == 0) {
751811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        result = "[None]";
751911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else {
752011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        result = "[";
752111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (auto i = 0; i < 32; i++) {
752211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (accessMask & (1 << i)) {
752311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                result = result + separator + string_VkAccessFlagBits((VkAccessFlagBits)(1 << i));
752411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                separator = " | ";
752511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
752611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
752711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        result = result + "]";
752811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
752911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
753011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
753111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
753211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// AccessFlags MUST have 'required_bit' set, and may have one or more of 'optional_bits' set.
753311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// If required_bit is zero, accessMask must have at least one of 'optional_bits' set
753411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// TODO: Add tracking to ensure that at least one barrier has been set for these layout transitions
753511cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool ValidateMaskBits(const layer_data *my_data, VkCommandBuffer cmdBuffer, const VkAccessFlags &accessMask,
753611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             const VkImageLayout &layout, VkAccessFlags required_bit, VkAccessFlags optional_bits,
753711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             const char *type) {
753811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
753911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
754011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if ((accessMask & required_bit) || (!required_bit && (accessMask & optional_bits))) {
754111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (accessMask & ~(required_bit | optional_bits)) {
754211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // TODO: Verify against Valid Use
754311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |=
754411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
754511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        DRAWSTATE_INVALID_BARRIER, "DS", "Additional bits in %s accessMask 0x%X %s are specified when layout is %s.",
754611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        type, accessMask, string_VkAccessFlags(accessMask).c_str(), string_VkImageLayout(layout));
754711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
754811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else {
754911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!required_bit) {
755011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
755111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 DRAWSTATE_INVALID_BARRIER, "DS", "%s AccessMask %d %s must contain at least one of access bits %d "
755211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                  "%s when layout is %s, unless the app has previously added a "
755311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                  "barrier for this transition.",
755411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 type, accessMask, string_VkAccessFlags(accessMask).c_str(), optional_bits,
755511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 string_VkAccessFlags(optional_bits).c_str(), string_VkImageLayout(layout));
755611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
755711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            std::string opt_bits;
755811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (optional_bits != 0) {
755911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                std::stringstream ss;
756011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                ss << optional_bits;
756111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                opt_bits = "and may have optional bits " + ss.str() + ' ' + string_VkAccessFlags(optional_bits);
756211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
756311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
756411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 DRAWSTATE_INVALID_BARRIER, "DS", "%s AccessMask %d %s must have required access bit %d %s %s when "
756511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                  "layout is %s, unless the app has previously added a barrier for "
756611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                  "this transition.",
756711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 type, accessMask, string_VkAccessFlags(accessMask).c_str(), required_bit,
756811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 string_VkAccessFlags(required_bit).c_str(), opt_bits.c_str(), string_VkImageLayout(layout));
756911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
757011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
757111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skip_call;
757211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
757311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
757411cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool ValidateMaskBitsFromLayouts(const layer_data *my_data, VkCommandBuffer cmdBuffer, const VkAccessFlags &accessMask,
757511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        const VkImageLayout &layout, const char *type) {
757611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
757711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    switch (layout) {
757811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: {
757911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
758011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                      VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, type);
758111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        break;
758211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
758311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: {
758411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
758511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                      VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, type);
758611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        break;
758711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
758811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: {
758911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, VK_ACCESS_TRANSFER_WRITE_BIT, 0, type);
759011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        break;
759111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
759211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_IMAGE_LAYOUT_PREINITIALIZED: {
759311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, VK_ACCESS_HOST_WRITE_BIT, 0, type);
759411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        break;
759511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
759611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: {
759711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, 0,
759811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                      VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT, type);
759911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        break;
760011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
760111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: {
760211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, 0,
760311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                      VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT, type);
760411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        break;
760511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
760611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: {
760711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, VK_ACCESS_TRANSFER_READ_BIT, 0, type);
760811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        break;
760911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
761011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_IMAGE_LAYOUT_UNDEFINED: {
761111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (accessMask != 0) {
761211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // TODO: Verify against Valid Use section spec
761311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |=
761411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
761511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        DRAWSTATE_INVALID_BARRIER, "DS", "Additional bits in %s accessMask 0x%X %s are specified when layout is %s.",
761611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        type, accessMask, string_VkAccessFlags(accessMask).c_str(), string_VkImageLayout(layout));
761711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
761811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        break;
761911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
762011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    case VK_IMAGE_LAYOUT_GENERAL:
762111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    default: { break; }
762211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
762311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skip_call;
762411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
762511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
762611cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool ValidateBarriers(const char *funcName, VkCommandBuffer cmdBuffer, uint32_t memBarrierCount,
762711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             const VkMemoryBarrier *pMemBarriers, uint32_t bufferBarrierCount,
762811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             const VkBufferMemoryBarrier *pBufferMemBarriers, uint32_t imageMemBarrierCount,
762911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             const VkImageMemoryBarrier *pImageMemBarriers) {
763011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
763111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map);
763211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer);
763311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB->activeRenderPass && memBarrierCount) {
763411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!pCB->activeRenderPass->hasSelfDependency[pCB->activeSubpass]) {
763511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
763611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 DRAWSTATE_INVALID_BARRIER, "DS", "%s: Barriers cannot be set during subpass %d "
763711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                  "with no self dependency specified.",
763811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 funcName, pCB->activeSubpass);
763911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
764011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
764111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < imageMemBarrierCount; ++i) {
764211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto mem_barrier = &pImageMemBarriers[i];
764311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto image_data = dev_data->imageMap.find(mem_barrier->image);
764411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (image_data != dev_data->imageMap.end()) {
764511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            uint32_t src_q_f_index = mem_barrier->srcQueueFamilyIndex;
764611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            uint32_t dst_q_f_index = mem_barrier->dstQueueFamilyIndex;
764711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (image_data->second.createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) {
764811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                // srcQueueFamilyIndex and dstQueueFamilyIndex must both
764911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                // be VK_QUEUE_FAMILY_IGNORED
765011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if ((src_q_f_index != VK_QUEUE_FAMILY_IGNORED) || (dst_q_f_index != VK_QUEUE_FAMILY_IGNORED)) {
765111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
765211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         __LINE__, DRAWSTATE_INVALID_QUEUE_INDEX, "DS",
765311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         "%s: Image Barrier for image 0x%" PRIx64 " was created with sharingMode of "
765411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         "VK_SHARING_MODE_CONCURRENT.  Src and dst "
765511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         " queueFamilyIndices must be VK_QUEUE_FAMILY_IGNORED.",
765611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         funcName, reinterpret_cast<const uint64_t &>(mem_barrier->image));
765711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
765811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            } else {
765911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                // Sharing mode is VK_SHARING_MODE_EXCLUSIVE. srcQueueFamilyIndex and
766011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                // dstQueueFamilyIndex must either both be VK_QUEUE_FAMILY_IGNORED,
766111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                // or both be a valid queue family
766211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (((src_q_f_index == VK_QUEUE_FAMILY_IGNORED) || (dst_q_f_index == VK_QUEUE_FAMILY_IGNORED)) &&
766311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    (src_q_f_index != dst_q_f_index)) {
766411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skip_call |=
766511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
766611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                DRAWSTATE_INVALID_QUEUE_INDEX, "DS", "%s: Image 0x%" PRIx64 " was created with sharingMode "
766711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                     "of VK_SHARING_MODE_EXCLUSIVE. If one of src- or "
766811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                     "dstQueueFamilyIndex is VK_QUEUE_FAMILY_IGNORED, both "
766911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                     "must be.",
767011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                funcName, reinterpret_cast<const uint64_t &>(mem_barrier->image));
767111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                } else if (((src_q_f_index != VK_QUEUE_FAMILY_IGNORED) && (dst_q_f_index != VK_QUEUE_FAMILY_IGNORED)) &&
767211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                           ((src_q_f_index >= dev_data->phys_dev_properties.queue_family_properties.size()) ||
767311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            (dst_q_f_index >= dev_data->phys_dev_properties.queue_family_properties.size()))) {
767411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
767511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         __LINE__, DRAWSTATE_INVALID_QUEUE_INDEX, "DS",
767611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         "%s: Image 0x%" PRIx64 " was created with sharingMode "
767711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         "of VK_SHARING_MODE_EXCLUSIVE, but srcQueueFamilyIndex %d"
767811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         " or dstQueueFamilyIndex %d is greater than " PRINTF_SIZE_T_SPECIFIER
767911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         "queueFamilies crated for this device.",
768011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         funcName, reinterpret_cast<const uint64_t &>(mem_barrier->image), src_q_f_index,
768111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         dst_q_f_index, dev_data->phys_dev_properties.queue_family_properties.size());
768211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
768311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
768411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
768511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
768611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (mem_barrier) {
768711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |=
768811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                ValidateMaskBitsFromLayouts(dev_data, cmdBuffer, mem_barrier->srcAccessMask, mem_barrier->oldLayout, "Source");
768911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |=
769011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                ValidateMaskBitsFromLayouts(dev_data, cmdBuffer, mem_barrier->dstAccessMask, mem_barrier->newLayout, "Dest");
769111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (mem_barrier->newLayout == VK_IMAGE_LAYOUT_UNDEFINED || mem_barrier->newLayout == VK_IMAGE_LAYOUT_PREINITIALIZED) {
769211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
769311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        DRAWSTATE_INVALID_BARRIER, "DS", "%s: Image Layout cannot be transitioned to UNDEFINED or "
769411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                         "PREINITIALIZED.",
769511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        funcName);
769611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
769711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            auto image_data = dev_data->imageMap.find(mem_barrier->image);
769811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            VkFormat format = VK_FORMAT_UNDEFINED;
769911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            uint32_t arrayLayers = 0, mipLevels = 0;
770011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            bool imageFound = false;
770111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (image_data != dev_data->imageMap.end()) {
770211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                format = image_data->second.createInfo.format;
770311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                arrayLayers = image_data->second.createInfo.arrayLayers;
770411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                mipLevels = image_data->second.createInfo.mipLevels;
770511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                imageFound = true;
770611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            } else if (dev_data->device_extensions.wsi_enabled) {
770711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                auto imageswap_data = dev_data->device_extensions.imageToSwapchainMap.find(mem_barrier->image);
770811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (imageswap_data != dev_data->device_extensions.imageToSwapchainMap.end()) {
770911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    auto swapchain_data = dev_data->device_extensions.swapchainMap.find(imageswap_data->second);
771011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    if (swapchain_data != dev_data->device_extensions.swapchainMap.end()) {
771111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        format = swapchain_data->second->createInfo.imageFormat;
771211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        arrayLayers = swapchain_data->second->createInfo.imageArrayLayers;
771311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        mipLevels = 1;
771411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        imageFound = true;
771511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    }
771611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
771711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
771811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (imageFound) {
771911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (vk_format_is_depth_and_stencil(format) &&
772011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    (!(mem_barrier->subresourceRange.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) ||
772111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                     !(mem_barrier->subresourceRange.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT))) {
772211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
772311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            DRAWSTATE_INVALID_BARRIER, "DS", "%s: Image is a depth and stencil format and thus must "
772411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                             "have both VK_IMAGE_ASPECT_DEPTH_BIT and "
772511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                             "VK_IMAGE_ASPECT_STENCIL_BIT set.",
772611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            funcName);
772711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
772811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                int layerCount = (mem_barrier->subresourceRange.layerCount == VK_REMAINING_ARRAY_LAYERS)
772911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                     ? 1
773011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                     : mem_barrier->subresourceRange.layerCount;
773111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if ((mem_barrier->subresourceRange.baseArrayLayer + layerCount) > arrayLayers) {
773211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
773311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            DRAWSTATE_INVALID_BARRIER, "DS", "%s: Subresource must have the sum of the "
773411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                             "baseArrayLayer (%d) and layerCount (%d) be less "
773511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                             "than or equal to the total number of layers (%d).",
773611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            funcName, mem_barrier->subresourceRange.baseArrayLayer, mem_barrier->subresourceRange.layerCount,
773711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            arrayLayers);
773811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
773911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                int levelCount = (mem_barrier->subresourceRange.levelCount == VK_REMAINING_MIP_LEVELS)
774011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                     ? 1
774111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                     : mem_barrier->subresourceRange.levelCount;
774211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if ((mem_barrier->subresourceRange.baseMipLevel + levelCount) > mipLevels) {
774311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
774411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            DRAWSTATE_INVALID_BARRIER, "DS", "%s: Subresource must have the sum of the baseMipLevel "
774511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                             "(%d) and levelCount (%d) be less than or equal to "
774611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                             "the total number of levels (%d).",
774711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            funcName, mem_barrier->subresourceRange.baseMipLevel, mem_barrier->subresourceRange.levelCount,
774811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            mipLevels);
774911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
775011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
775111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
775211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
775311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < bufferBarrierCount; ++i) {
775411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto mem_barrier = &pBufferMemBarriers[i];
775511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (pCB->activeRenderPass) {
775611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |=
775711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
775811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        DRAWSTATE_INVALID_BARRIER, "DS", "%s: Buffer Barriers cannot be used during a render pass.", funcName);
775911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
776011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!mem_barrier)
776111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            continue;
776211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
776311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Validate buffer barrier queue family indices
776411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if ((mem_barrier->srcQueueFamilyIndex != VK_QUEUE_FAMILY_IGNORED &&
776511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert             mem_barrier->srcQueueFamilyIndex >= dev_data->phys_dev_properties.queue_family_properties.size()) ||
776611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            (mem_barrier->dstQueueFamilyIndex != VK_QUEUE_FAMILY_IGNORED &&
776711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert             mem_barrier->dstQueueFamilyIndex >= dev_data->phys_dev_properties.queue_family_properties.size())) {
776811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
776911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 DRAWSTATE_INVALID_QUEUE_INDEX, "DS",
777011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 "%s: Buffer Barrier 0x%" PRIx64 " has QueueFamilyIndex greater "
777111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 "than the number of QueueFamilies (" PRINTF_SIZE_T_SPECIFIER ") for this device.",
777211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 funcName, reinterpret_cast<const uint64_t &>(mem_barrier->buffer),
777311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 dev_data->phys_dev_properties.queue_family_properties.size());
777411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
777511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
777611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto buffer_data = dev_data->bufferMap.find(mem_barrier->buffer);
777711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (buffer_data != dev_data->bufferMap.end()) {
777811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            VkDeviceSize buffer_size = (buffer_data->second.createInfo.sType == VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO)
777911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                           ? buffer_data->second.createInfo.size
778011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                           : 0;
778111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (mem_barrier->offset >= buffer_size) {
778211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skip_call |= log_msg(
778311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
778411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    DRAWSTATE_INVALID_BARRIER, "DS",
778511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    "%s: Buffer Barrier 0x%" PRIx64 " has offset 0x%" PRIx64 " which is not less than total size 0x%" PRIx64 ".",
778611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    funcName, reinterpret_cast<const uint64_t &>(mem_barrier->buffer),
778711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    reinterpret_cast<const uint64_t &>(mem_barrier->offset), reinterpret_cast<const uint64_t &>(buffer_size));
778811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            } else if (mem_barrier->size != VK_WHOLE_SIZE && (mem_barrier->offset + mem_barrier->size > buffer_size)) {
778911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skip_call |= log_msg(
779011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
779111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    DRAWSTATE_INVALID_BARRIER, "DS", "%s: Buffer Barrier 0x%" PRIx64 " has offset 0x%" PRIx64 " and size 0x%" PRIx64
779211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                     " whose sum is greater than total size 0x%" PRIx64 ".",
779311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    funcName, reinterpret_cast<const uint64_t &>(mem_barrier->buffer),
779411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    reinterpret_cast<const uint64_t &>(mem_barrier->offset), reinterpret_cast<const uint64_t &>(mem_barrier->size),
779511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    reinterpret_cast<const uint64_t &>(buffer_size));
779611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
779711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
779811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
779911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skip_call;
780011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
780111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
780211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertbool validateEventStageMask(VkQueue queue, GLOBAL_CB_NODE *pCB, uint32_t eventCount, size_t firstEventIndex, VkPipelineStageFlags sourceStageMask) {
780311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
780411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkPipelineStageFlags stageMask = 0;
780511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map);
780611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < eventCount; ++i) {
780711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto event = pCB->events[firstEventIndex + i];
780811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto queue_data = dev_data->queueMap.find(queue);
780911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (queue_data == dev_data->queueMap.end())
781011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return false;
781111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto event_data = queue_data->second.eventToStageMap.find(event);
781211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (event_data != queue_data->second.eventToStageMap.end()) {
781311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            stageMask |= event_data->second;
781411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
781511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            auto global_event_data = dev_data->eventMap.find(event);
781611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (global_event_data == dev_data->eventMap.end()) {
781711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT,
781811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                     reinterpret_cast<const uint64_t &>(event), __LINE__, DRAWSTATE_INVALID_EVENT, "DS",
781911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                     "Event 0x%" PRIx64 " cannot be waited on if it has never been set.",
782011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                     reinterpret_cast<const uint64_t &>(event));
782111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            } else {
782211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                stageMask |= global_event_data->second.stageMask;
782311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
782411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
782511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
782611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODO: Need to validate that host_bit is only set if set event is called
782711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // but set event can be called at any time.
782811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (sourceStageMask != stageMask && sourceStageMask != (stageMask | VK_PIPELINE_STAGE_HOST_BIT)) {
782911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
783011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             DRAWSTATE_INVALID_EVENT, "DS", "Submitting cmdbuffer with call to VkCmdWaitEvents "
783111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                            "using srcStageMask 0x%x which must be the bitwise "
783211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                            "OR of the stageMask parameters used in calls to "
783311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                            "vkCmdSetEvent and VK_PIPELINE_STAGE_HOST_BIT if "
783411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                            "used with vkSetEvent but instead is 0x%x.",
783511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             sourceStageMask, stageMask);
783611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
783711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skip_call;
783811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
783911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
784011cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
784111cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents, VkPipelineStageFlags sourceStageMask,
784211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert              VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
784311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert              uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
784411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert              uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
784511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
784611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
784711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
784811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
784911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
785011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto firstEventIndex = pCB->events.size();
785111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t i = 0; i < eventCount; ++i) {
785211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pCB->waitedEvents.insert(pEvents[i]);
785311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pCB->events.push_back(pEvents[i]);
785411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
785511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::function<bool(VkQueue)> eventUpdate =
785611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            std::bind(validateEventStageMask, std::placeholders::_1, pCB, eventCount, firstEventIndex, sourceStageMask);
785711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->eventUpdates.push_back(eventUpdate);
785811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (pCB->state == CB_RECORDING) {
785911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= addCmd(dev_data, pCB, CMD_WAITEVENTS, "vkCmdWaitEvents()");
786011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
786111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdWaitEvents()");
786211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
786311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= TransitionImageLayouts(commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers);
786411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |=
786511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            ValidateBarriers("vkCmdWaitEvents", commandBuffer, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
786611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
786711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
786811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
786911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
787011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdWaitEvents(commandBuffer, eventCount, pEvents, sourceStageMask, dstStageMask,
787111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                       memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
787211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                       pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
787311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
787411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
787511cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
787611cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask,
787711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                   VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
787811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                   uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
787911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                   uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
788011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
788111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
788211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
788311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
788411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
788511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= addCmd(dev_data, pCB, CMD_PIPELINEBARRIER, "vkCmdPipelineBarrier()");
788611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= TransitionImageLayouts(commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers);
788711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |=
788811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            ValidateBarriers("vkCmdPipelineBarrier", commandBuffer, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
788911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
789011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
789111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
789211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
789311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, dependencyFlags,
789411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                            memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
789511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                            pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
789611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
789711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
789811cd02dfb91661c65134cac258cf5924270e9d2Dan Albertbool setQueryState(VkQueue queue, VkCommandBuffer commandBuffer, QueryObject object, bool value) {
789911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
790011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
790111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
790211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->queryToStateMap[object] = value;
790311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
790411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto queue_data = dev_data->queueMap.find(queue);
790511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (queue_data != dev_data->queueMap.end()) {
790611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        queue_data->second.queryToStateMap[object] = value;
790711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
790811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return false;
790911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
791011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
791111cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
791211cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCmdBeginQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot, VkFlags flags) {
791311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
791411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
791511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
791611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
791711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
791811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        QueryObject query = {queryPool, slot};
791911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->activeQueries.insert(query);
792011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!pCB->startedQueries.count(query)) {
792111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pCB->startedQueries.insert(query);
792211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
792311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= addCmd(dev_data, pCB, CMD_BEGINQUERY, "vkCmdBeginQuery()");
792411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
792511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
792611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
792711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdBeginQuery(commandBuffer, queryPool, slot, flags);
792811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
792911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
793011cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL CmdEndQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot) {
793111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
793211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
793311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
793411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
793511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
793611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        QueryObject query = {queryPool, slot};
793711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!pCB->activeQueries.count(query)) {
793811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |=
793911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
794011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        DRAWSTATE_INVALID_QUERY, "DS", "Ending a query before it was started: queryPool 0x%" PRIx64 ", index %d",
794111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        (uint64_t)(queryPool), slot);
794211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
794311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pCB->activeQueries.erase(query);
794411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
794511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::function<bool(VkQueue)> queryUpdate = std::bind(setQueryState, std::placeholders::_1, commandBuffer, query, true);
794611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->queryUpdates.push_back(queryUpdate);
794711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (pCB->state == CB_RECORDING) {
794811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= addCmd(dev_data, pCB, CMD_ENDQUERY, "VkCmdEndQuery()");
794911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
795011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdEndQuery()");
795111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
795211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
795311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
795411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
795511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdEndQuery(commandBuffer, queryPool, slot);
795611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
795711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
795811cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
795911cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCmdResetQueryPool(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount) {
796011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
796111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
796211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
796311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
796411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
796511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t i = 0; i < queryCount; i++) {
796611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            QueryObject query = {queryPool, firstQuery + i};
796711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pCB->waitedEventsBeforeQueryReset[query] = pCB->waitedEvents;
796811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            std::function<bool(VkQueue)> queryUpdate = std::bind(setQueryState, std::placeholders::_1, commandBuffer, query, false);
796911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pCB->queryUpdates.push_back(queryUpdate);
797011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
797111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (pCB->state == CB_RECORDING) {
797211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= addCmd(dev_data, pCB, CMD_RESETQUERYPOOL, "VkCmdResetQueryPool()");
797311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
797411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdResetQueryPool()");
797511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
797611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= insideRenderPass(dev_data, pCB, "vkCmdQueryPool");
797711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
797811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
797911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
798011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdResetQueryPool(commandBuffer, queryPool, firstQuery, queryCount);
798111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
798211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
798311cd02dfb91661c65134cac258cf5924270e9d2Dan Albertbool validateQuery(VkQueue queue, GLOBAL_CB_NODE *pCB, VkQueryPool queryPool, uint32_t queryCount, uint32_t firstQuery) {
798411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
798511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(pCB->commandBuffer), layer_data_map);
798611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto queue_data = dev_data->queueMap.find(queue);
798711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (queue_data == dev_data->queueMap.end())
798811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return false;
798911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < queryCount; i++) {
799011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        QueryObject query = {queryPool, firstQuery + i};
799111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto query_data = queue_data->second.queryToStateMap.find(query);
799211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        bool fail = false;
799311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (query_data != queue_data->second.queryToStateMap.end()) {
799411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (!query_data->second) {
799511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                fail = true;
799611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
799711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
799811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            auto global_query_data = dev_data->queryToStateMap.find(query);
799911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (global_query_data != dev_data->queryToStateMap.end()) {
800011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (!global_query_data->second) {
800111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    fail = true;
800211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
800311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            } else {
800411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                fail = true;
800511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
800611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
800711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (fail) {
800811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
800911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 DRAWSTATE_INVALID_QUERY, "DS",
801011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 "Requesting a copy from query to buffer with invalid query: queryPool 0x%" PRIx64 ", index %d",
801111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 reinterpret_cast<uint64_t &>(queryPool), firstQuery + i);
801211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
801311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
801411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skip_call;
801511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
801611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
801711cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
801811cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCmdCopyQueryPoolResults(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount,
801911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags) {
802011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
802111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
802211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
802311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
802411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#if MTMERGESOURCE
802511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkDeviceMemory mem;
802611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
802711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |=
802811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        get_mem_binding_from_object(dev_data, (uint64_t)dstBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
802911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (cb_data != dev_data->commandBufferMap.end()) {
803011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::function<bool()> function = [=]() {
803111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            set_memory_valid(dev_data, mem, true);
803211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return false;
803311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        };
803411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        cb_data->second->validate_functions.push_back(function);
803511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
803611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyQueryPoolResults");
803711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Validate that DST buffer has correct usage flags set
803811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= validate_buffer_usage_flags(dev_data, dstBuffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true,
803911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            "vkCmdCopyQueryPoolResults()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
804011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#endif
804111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
804211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::function<bool(VkQueue)> queryUpdate =
804311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            std::bind(validateQuery, std::placeholders::_1, pCB, queryPool, queryCount, firstQuery);
804411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->queryUpdates.push_back(queryUpdate);
804511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (pCB->state == CB_RECORDING) {
804611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= addCmd(dev_data, pCB, CMD_COPYQUERYPOOLRESULTS, "vkCmdCopyQueryPoolResults()");
804711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
804811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdCopyQueryPoolResults()");
804911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
805011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyQueryPoolResults");
805111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
805211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
805311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
805411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdCopyQueryPoolResults(commandBuffer, queryPool, firstQuery, queryCount, dstBuffer,
805511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                 dstOffset, stride, flags);
805611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
805711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
805811cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL CmdPushConstants(VkCommandBuffer commandBuffer, VkPipelineLayout layout,
805911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size,
806011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            const void *pValues) {
806111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
806211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
806311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
806411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
806511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
806611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (pCB->state == CB_RECORDING) {
806711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= addCmd(dev_data, pCB, CMD_PUSHCONSTANTS, "vkCmdPushConstants()");
806811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
806911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdPushConstants()");
807011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
807111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
807211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= validatePushConstantRange(dev_data, offset, size, "vkCmdPushConstants()");
807311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (0 == stageFlags) {
807411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
807511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            DRAWSTATE_PUSH_CONSTANTS_ERROR, "DS", "vkCmdPushConstants() call has no stageFlags set.");
807611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
807711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
807811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Check if push constant update is within any of the ranges with the same stage flags specified in pipeline layout.
807911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto pipeline_layout = getPipelineLayout(dev_data, layout);
808011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!pipeline_layout) {
808111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
808211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            DRAWSTATE_PUSH_CONSTANTS_ERROR, "DS", "vkCmdPushConstants() Pipeline Layout 0x%" PRIx64 " not found.",
808311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            (uint64_t)layout);
808411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else {
808511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Coalesce adjacent/overlapping pipeline ranges before checking to see if incoming range is
808611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // contained in the pipeline ranges.
808711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Build a {start, end} span list for ranges with matching stage flags.
808811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        const auto &ranges = pipeline_layout->pushConstantRanges;
808911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        struct span {
809011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            uint32_t start;
809111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            uint32_t end;
809211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        };
809311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::vector<span> spans;
809411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        spans.reserve(ranges.size());
809511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (const auto &iter : ranges) {
809611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (iter.stageFlags == stageFlags) {
809711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                spans.push_back({iter.offset, iter.offset + iter.size});
809811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
809911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
810011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (spans.size() == 0) {
810111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // There were no ranges that matched the stageFlags.
810211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
810311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                DRAWSTATE_PUSH_CONSTANTS_ERROR, "DS",
810411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                "vkCmdPushConstants() stageFlags = 0x%" PRIx32 " do not match "
810511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                "the stageFlags in any of the ranges in pipeline layout 0x%" PRIx64 ".",
810611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                (uint32_t)stageFlags, (uint64_t)layout);
810711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
810811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // Sort span list by start value.
810911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            struct comparer {
811011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                bool operator()(struct span i, struct span j) { return i.start < j.start; }
811111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            } my_comparer;
811211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            std::sort(spans.begin(), spans.end(), my_comparer);
811311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
811411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // Examine two spans at a time.
811511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            std::vector<span>::iterator current = spans.begin();
811611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            std::vector<span>::iterator next = current + 1;
811711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            while (next != spans.end()) {
811811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (current->end < next->start) {
811911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    // There is a gap; cannot coalesce. Move to the next two spans.
812011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    ++current;
812111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    ++next;
812211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                } else {
812311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    // Coalesce the two spans.  The start of the next span
812411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    // is within the current span, so pick the larger of
812511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    // the end values to extend the current span.
812611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    // Then delete the next span and set next to the span after it.
812711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    current->end = max(current->end, next->end);
812811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    next = spans.erase(next);
812911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
813011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
813111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
813211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // Now we can check if the incoming range is within any of the spans.
813311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            bool contained_in_a_range = false;
813411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (uint32_t i = 0; i < spans.size(); ++i) {
813511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if ((offset >= spans[i].start) && ((uint64_t)offset + (uint64_t)size <= (uint64_t)spans[i].end)) {
813611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    contained_in_a_range = true;
813711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    break;
813811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
813911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
814011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (!contained_in_a_range) {
814111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
814211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    __LINE__, DRAWSTATE_PUSH_CONSTANTS_ERROR, "DS",
814311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    "vkCmdPushConstants() Push constant range [%d, %d) "
814411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    "with stageFlags = 0x%" PRIx32 " "
814511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    "not within flag-matching ranges in pipeline layout 0x%" PRIx64 ".",
814611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    offset, offset + size, (uint32_t)stageFlags, (uint64_t)layout);
814711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
814811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
814911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
815011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
815111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
815211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdPushConstants(commandBuffer, layout, stageFlags, offset, size, pValues);
815311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
815411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
815511cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
815611cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, uint32_t slot) {
815711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
815811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
815911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
816011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
816111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
816211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        QueryObject query = {queryPool, slot};
816311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::function<bool(VkQueue)> queryUpdate = std::bind(setQueryState, std::placeholders::_1, commandBuffer, query, true);
816411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->queryUpdates.push_back(queryUpdate);
816511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (pCB->state == CB_RECORDING) {
816611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= addCmd(dev_data, pCB, CMD_WRITETIMESTAMP, "vkCmdWriteTimestamp()");
816711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
816811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdWriteTimestamp()");
816911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
817011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
817111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
817211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
817311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdWriteTimestamp(commandBuffer, pipelineStage, queryPool, slot);
817411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
817511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
817611cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL CreateFramebuffer(VkDevice device, const VkFramebufferCreateInfo *pCreateInfo,
817711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                 const VkAllocationCallbacks *pAllocator,
817811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                 VkFramebuffer *pFramebuffer) {
817911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
818011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = dev_data->device_dispatch_table->CreateFramebuffer(device, pCreateInfo, pAllocator, pFramebuffer);
818111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (VK_SUCCESS == result) {
818211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Shadow create info and store in map
818311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::lock_guard<std::mutex> lock(global_lock);
818411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
818511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto & fbNode = dev_data->frameBufferMap[*pFramebuffer];
818611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        fbNode.createInfo = *pCreateInfo;
818711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (pCreateInfo->pAttachments) {
818811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            auto attachments = new VkImageView[pCreateInfo->attachmentCount];
818911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            memcpy(attachments,
819011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                   pCreateInfo->pAttachments,
819111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                   pCreateInfo->attachmentCount * sizeof(VkImageView));
819211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            fbNode.createInfo.pAttachments = attachments;
819311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
819411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
819511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            VkImageView view = pCreateInfo->pAttachments[i];
819611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            auto view_data = dev_data->imageViewMap.find(view);
819711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (view_data == dev_data->imageViewMap.end()) {
819811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                continue;
819911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
820011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            MT_FB_ATTACHMENT_INFO fb_info;
820111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            get_mem_binding_from_object(dev_data, (uint64_t)(view_data->second.image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
820211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        &fb_info.mem);
820311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            fb_info.image = view_data->second.image;
820411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            fbNode.attachments.push_back(fb_info);
820511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
820611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
820711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
820811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
820911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
821011cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool FindDependency(const int index, const int dependent, const std::vector<DAGNode> &subpass_to_node,
821111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                           std::unordered_set<uint32_t> &processed_nodes) {
821211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // If we have already checked this node we have not found a dependency path so return false.
821311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (processed_nodes.count(index))
821411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return false;
821511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    processed_nodes.insert(index);
821611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    const DAGNode &node = subpass_to_node[index];
821711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Look for a dependency path. If one exists return true else recurse on the previous nodes.
821811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (std::find(node.prev.begin(), node.prev.end(), dependent) == node.prev.end()) {
821911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (auto elem : node.prev) {
822011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (FindDependency(elem, dependent, subpass_to_node, processed_nodes))
822111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                return true;
822211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
822311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else {
822411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return true;
822511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
822611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return false;
822711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
822811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
822911cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool CheckDependencyExists(const layer_data *my_data, const int subpass, const std::vector<uint32_t> &dependent_subpasses,
823011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                  const std::vector<DAGNode> &subpass_to_node, bool &skip_call) {
823111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool result = true;
823211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Loop through all subpasses that share the same attachment and make sure a dependency exists
823311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t k = 0; k < dependent_subpasses.size(); ++k) {
823411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (static_cast<uint32_t>(subpass) == dependent_subpasses[k])
823511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            continue;
823611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        const DAGNode &node = subpass_to_node[subpass];
823711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Check for a specified dependency between the two nodes. If one exists we are done.
823811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto prev_elem = std::find(node.prev.begin(), node.prev.end(), dependent_subpasses[k]);
823911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto next_elem = std::find(node.next.begin(), node.next.end(), dependent_subpasses[k]);
824011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (prev_elem == node.prev.end() && next_elem == node.next.end()) {
824111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // If no dependency exits an implicit dependency still might. If so, warn and if not throw an error.
824211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            std::unordered_set<uint32_t> processed_nodes;
824311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (FindDependency(subpass, dependent_subpasses[k], subpass_to_node, processed_nodes) ||
824411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                FindDependency(dependent_subpasses[k], subpass, subpass_to_node, processed_nodes)) {
824511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
824611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                     __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
824711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                     "A dependency between subpasses %d and %d must exist but only an implicit one is specified.",
824811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                     subpass, dependent_subpasses[k]);
824911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            } else {
825011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
825111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                     __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
825211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                     "A dependency between subpasses %d and %d must exist but one is not specified.", subpass,
825311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                     dependent_subpasses[k]);
825411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                result = false;
825511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
825611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
825711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
825811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
825911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
826011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
826111cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool CheckPreserved(const layer_data *my_data, const VkRenderPassCreateInfo *pCreateInfo, const int index,
826211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                           const uint32_t attachment, const std::vector<DAGNode> &subpass_to_node, int depth, bool &skip_call) {
826311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    const DAGNode &node = subpass_to_node[index];
826411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // If this node writes to the attachment return true as next nodes need to preserve the attachment.
826511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[index];
826611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
826711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (attachment == subpass.pColorAttachments[j].attachment)
826811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return true;
826911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
827011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
827111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (attachment == subpass.pDepthStencilAttachment->attachment)
827211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return true;
827311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
827411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool result = false;
827511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Loop through previous nodes and see if any of them write to the attachment.
827611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto elem : node.prev) {
827711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        result |= CheckPreserved(my_data, pCreateInfo, elem, attachment, subpass_to_node, depth + 1, skip_call);
827811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
827911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // If the attachment was written to by a previous node than this node needs to preserve it.
828011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (result && depth > 0) {
828111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[index];
828211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        bool has_preserved = false;
828311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t j = 0; j < subpass.preserveAttachmentCount; ++j) {
828411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (subpass.pPreserveAttachments[j] == attachment) {
828511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                has_preserved = true;
828611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                break;
828711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
828811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
828911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!has_preserved) {
829011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |=
829111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
829211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        DRAWSTATE_INVALID_RENDERPASS, "DS",
829311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "Attachment %d is used by a later subpass and must be preserved in subpass %d.", attachment, index);
829411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
829511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
829611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
829711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
829811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
829911cd02dfb91661c65134cac258cf5924270e9d2Dan Alberttemplate <class T> bool isRangeOverlapping(T offset1, T size1, T offset2, T size2) {
830011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return (((offset1 + size1) > offset2) && ((offset1 + size1) < (offset2 + size2))) ||
830111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert           ((offset1 > offset2) && (offset1 < (offset2 + size2)));
830211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
830311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
830411cd02dfb91661c65134cac258cf5924270e9d2Dan Albertbool isRegionOverlapping(VkImageSubresourceRange range1, VkImageSubresourceRange range2) {
830511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return (isRangeOverlapping(range1.baseMipLevel, range1.levelCount, range2.baseMipLevel, range2.levelCount) &&
830611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            isRangeOverlapping(range1.baseArrayLayer, range1.layerCount, range2.baseArrayLayer, range2.layerCount));
830711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
830811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
830911cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool ValidateDependencies(const layer_data *my_data, FRAMEBUFFER_NODE const * framebuffer,
831011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 RENDER_PASS_NODE const * renderPass) {
831111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
831211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    const VkFramebufferCreateInfo *pFramebufferInfo = &framebuffer->createInfo;
831311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    const VkRenderPassCreateInfo *pCreateInfo = renderPass->pCreateInfo;
831411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto const & subpass_to_node = renderPass->subpassToNode;
831511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::vector<std::vector<uint32_t>> output_attachment_to_subpass(pCreateInfo->attachmentCount);
831611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::vector<std::vector<uint32_t>> input_attachment_to_subpass(pCreateInfo->attachmentCount);
831711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::vector<std::vector<uint32_t>> overlapping_attachments(pCreateInfo->attachmentCount);
831811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Find overlapping attachments
831911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
832011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t j = i + 1; j < pCreateInfo->attachmentCount; ++j) {
832111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            VkImageView viewi = pFramebufferInfo->pAttachments[i];
832211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            VkImageView viewj = pFramebufferInfo->pAttachments[j];
832311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (viewi == viewj) {
832411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                overlapping_attachments[i].push_back(j);
832511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                overlapping_attachments[j].push_back(i);
832611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                continue;
832711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
832811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            auto view_data_i = my_data->imageViewMap.find(viewi);
832911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            auto view_data_j = my_data->imageViewMap.find(viewj);
833011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (view_data_i == my_data->imageViewMap.end() || view_data_j == my_data->imageViewMap.end()) {
833111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                continue;
833211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
833311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (view_data_i->second.image == view_data_j->second.image &&
833411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                isRegionOverlapping(view_data_i->second.subresourceRange, view_data_j->second.subresourceRange)) {
833511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                overlapping_attachments[i].push_back(j);
833611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                overlapping_attachments[j].push_back(i);
833711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                continue;
833811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
833911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            auto image_data_i = my_data->imageMap.find(view_data_i->second.image);
834011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            auto image_data_j = my_data->imageMap.find(view_data_j->second.image);
834111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (image_data_i == my_data->imageMap.end() || image_data_j == my_data->imageMap.end()) {
834211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                continue;
834311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
834411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (image_data_i->second.mem == image_data_j->second.mem &&
834511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                isRangeOverlapping(image_data_i->second.memOffset, image_data_i->second.memSize, image_data_j->second.memOffset,
834611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                   image_data_j->second.memSize)) {
834711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                overlapping_attachments[i].push_back(j);
834811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                overlapping_attachments[j].push_back(i);
834911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
835011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
835111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
835211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < overlapping_attachments.size(); ++i) {
835311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        uint32_t attachment = i;
835411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (auto other_attachment : overlapping_attachments[i]) {
835511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (!(pCreateInfo->pAttachments[attachment].flags & VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT)) {
835611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skip_call |=
835711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
835811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            DRAWSTATE_INVALID_RENDERPASS, "DS", "Attachment %d aliases attachment %d but doesn't "
835911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                "set VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT.",
836011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            attachment, other_attachment);
836111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
836211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (!(pCreateInfo->pAttachments[other_attachment].flags & VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT)) {
836311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skip_call |=
836411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
836511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            DRAWSTATE_INVALID_RENDERPASS, "DS", "Attachment %d aliases attachment %d but doesn't "
836611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                "set VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT.",
836711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            other_attachment, attachment);
836811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
836911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
837011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
837111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Find for each attachment the subpasses that use them.
837211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    unordered_set<uint32_t> attachmentIndices;
837311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
837411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
837511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        attachmentIndices.clear();
837611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
837711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            uint32_t attachment = subpass.pInputAttachments[j].attachment;
837811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            input_attachment_to_subpass[attachment].push_back(i);
837911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (auto overlapping_attachment : overlapping_attachments[attachment]) {
838011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                input_attachment_to_subpass[overlapping_attachment].push_back(i);
838111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
838211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
838311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
838411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            uint32_t attachment = subpass.pColorAttachments[j].attachment;
838511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            output_attachment_to_subpass[attachment].push_back(i);
838611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (auto overlapping_attachment : overlapping_attachments[attachment]) {
838711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                output_attachment_to_subpass[overlapping_attachment].push_back(i);
838811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
838911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            attachmentIndices.insert(attachment);
839011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
839111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
839211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            uint32_t attachment = subpass.pDepthStencilAttachment->attachment;
839311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            output_attachment_to_subpass[attachment].push_back(i);
839411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (auto overlapping_attachment : overlapping_attachments[attachment]) {
839511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                output_attachment_to_subpass[overlapping_attachment].push_back(i);
839611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
839711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
839811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (attachmentIndices.count(attachment)) {
839911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skip_call |=
840011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0,
840111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            0, __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
840211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "Cannot use same attachment (%u) as both color and depth output in same subpass (%u).",
840311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            attachment, i);
840411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
840511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
840611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
840711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // If there is a dependency needed make sure one exists
840811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
840911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
841011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // If the attachment is an input then all subpasses that output must have a dependency relationship
841111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
841211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            const uint32_t &attachment = subpass.pInputAttachments[j].attachment;
841311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            CheckDependencyExists(my_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip_call);
841411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
841511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // If the attachment is an output then all subpasses that use the attachment must have a dependency relationship
841611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
841711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            const uint32_t &attachment = subpass.pColorAttachments[j].attachment;
841811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            CheckDependencyExists(my_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip_call);
841911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            CheckDependencyExists(my_data, i, input_attachment_to_subpass[attachment], subpass_to_node, skip_call);
842011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
842111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
842211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            const uint32_t &attachment = subpass.pDepthStencilAttachment->attachment;
842311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            CheckDependencyExists(my_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip_call);
842411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            CheckDependencyExists(my_data, i, input_attachment_to_subpass[attachment], subpass_to_node, skip_call);
842511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
842611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
842711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Loop through implicit dependencies, if this pass reads make sure the attachment is preserved for all passes after it was
842811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // written.
842911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
843011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
843111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
843211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            CheckPreserved(my_data, pCreateInfo, i, subpass.pInputAttachments[j].attachment, subpass_to_node, 0, skip_call);
843311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
843411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
843511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skip_call;
843611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
843711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// ValidateLayoutVsAttachmentDescription is a general function where we can validate various state associated with the
843811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// VkAttachmentDescription structs that are used by the sub-passes of a renderpass. Initial check is to make sure that
843911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// READ_ONLY layout attachments don't have CLEAR as their loadOp.
844011cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool ValidateLayoutVsAttachmentDescription(debug_report_data *report_data, const VkImageLayout first_layout,
844111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                  const uint32_t attachment,
844211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                  const VkAttachmentDescription &attachment_description) {
844311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
844411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Verify that initial loadOp on READ_ONLY attachments is not CLEAR
844511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (attachment_description.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) {
844611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if ((first_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) ||
844711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            (first_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)) {
844811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |=
844911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
845011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        VkDebugReportObjectTypeEXT(0), __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
845111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "Cannot clear attachment %d with invalid first layout %s.", attachment, string_VkImageLayout(first_layout));
845211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
845311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
845411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skip_call;
845511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
845611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
845711cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool ValidateLayouts(const layer_data *my_data, VkDevice device, const VkRenderPassCreateInfo *pCreateInfo) {
845811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip = false;
845911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
846011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
846111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
846211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
846311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (subpass.pInputAttachments[j].layout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL &&
846411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                subpass.pInputAttachments[j].layout != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
846511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (subpass.pInputAttachments[j].layout == VK_IMAGE_LAYOUT_GENERAL) {
846611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    // TODO: Verify Valid Use in spec. I believe this is allowed (valid) but may not be optimal performance
846711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skip |= log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
846811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    (VkDebugReportObjectTypeEXT)0, 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
846911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    "Layout for input attachment is GENERAL but should be READ_ONLY_OPTIMAL.");
847011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                } else {
847111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skip |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
847211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
847311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    "Layout for input attachment is %s but can only be READ_ONLY_OPTIMAL or GENERAL.",
847411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    string_VkImageLayout(subpass.pInputAttachments[j].layout));
847511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
847611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
847711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            auto attach_index = subpass.pInputAttachments[j].attachment;
847811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip |= ValidateLayoutVsAttachmentDescription(my_data->report_data, subpass.pInputAttachments[j].layout, attach_index,
847911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                          pCreateInfo->pAttachments[attach_index]);
848011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
848111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
848211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (subpass.pColorAttachments[j].layout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
848311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (subpass.pColorAttachments[j].layout == VK_IMAGE_LAYOUT_GENERAL) {
848411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    // TODO: Verify Valid Use in spec. I believe this is allowed (valid) but may not be optimal performance
848511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skip |= log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
848611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    (VkDebugReportObjectTypeEXT)0, 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
848711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    "Layout for color attachment is GENERAL but should be COLOR_ATTACHMENT_OPTIMAL.");
848811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                } else {
848911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skip |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
849011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
849111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    "Layout for color attachment is %s but can only be COLOR_ATTACHMENT_OPTIMAL or GENERAL.",
849211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    string_VkImageLayout(subpass.pColorAttachments[j].layout));
849311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
849411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
849511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            auto attach_index = subpass.pColorAttachments[j].attachment;
849611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip |= ValidateLayoutVsAttachmentDescription(my_data->report_data, subpass.pColorAttachments[j].layout, attach_index,
849711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                          pCreateInfo->pAttachments[attach_index]);
849811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
849911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if ((subpass.pDepthStencilAttachment != NULL) && (subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED)) {
850011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (subpass.pDepthStencilAttachment->layout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
850111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (subpass.pDepthStencilAttachment->layout == VK_IMAGE_LAYOUT_GENERAL) {
850211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    // TODO: Verify Valid Use in spec. I believe this is allowed (valid) but may not be optimal performance
850311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skip |= log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
850411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    (VkDebugReportObjectTypeEXT)0, 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
850511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    "Layout for depth attachment is GENERAL but should be DEPTH_STENCIL_ATTACHMENT_OPTIMAL.");
850611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                } else {
850711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skip |=
850811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
850911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
851011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                "Layout for depth attachment is %s but can only be DEPTH_STENCIL_ATTACHMENT_OPTIMAL or GENERAL.",
851111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                string_VkImageLayout(subpass.pDepthStencilAttachment->layout));
851211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
851311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
851411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            auto attach_index = subpass.pDepthStencilAttachment->attachment;
851511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip |= ValidateLayoutVsAttachmentDescription(my_data->report_data, subpass.pDepthStencilAttachment->layout,
851611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                          attach_index, pCreateInfo->pAttachments[attach_index]);
851711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
851811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
851911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skip;
852011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
852111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
852211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool CreatePassDAG(const layer_data *my_data, VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
852311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                          std::vector<DAGNode> &subpass_to_node, std::vector<bool> &has_self_dependency) {
852411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
852511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
852611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        DAGNode &subpass_node = subpass_to_node[i];
852711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        subpass_node.pass = i;
852811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
852911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < pCreateInfo->dependencyCount; ++i) {
853011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        const VkSubpassDependency &dependency = pCreateInfo->pDependencies[i];
853111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (dependency.srcSubpass > dependency.dstSubpass && dependency.srcSubpass != VK_SUBPASS_EXTERNAL &&
853211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            dependency.dstSubpass != VK_SUBPASS_EXTERNAL) {
853311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
853411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 DRAWSTATE_INVALID_RENDERPASS, "DS",
853511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 "Depedency graph must be specified such that an earlier pass cannot depend on a later pass.");
853611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else if (dependency.srcSubpass == VK_SUBPASS_EXTERNAL && dependency.dstSubpass == VK_SUBPASS_EXTERNAL) {
853711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
853811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 DRAWSTATE_INVALID_RENDERPASS, "DS", "The src and dest subpasses cannot both be external.");
853911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else if (dependency.srcSubpass == dependency.dstSubpass) {
854011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            has_self_dependency[dependency.srcSubpass] = true;
854111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
854211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (dependency.dstSubpass != VK_SUBPASS_EXTERNAL) {
854311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            subpass_to_node[dependency.dstSubpass].prev.push_back(dependency.srcSubpass);
854411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
854511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (dependency.srcSubpass != VK_SUBPASS_EXTERNAL) {
854611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            subpass_to_node[dependency.srcSubpass].next.push_back(dependency.dstSubpass);
854711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
854811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
854911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skip_call;
855011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
855111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
855211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
855311cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL CreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo,
855411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                  const VkAllocationCallbacks *pAllocator,
855511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                  VkShaderModule *pShaderModule) {
855611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
855711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
855811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
855911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    /* Use SPIRV-Tools validator to try and catch any issues with the module itself */
856011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    spv_context ctx = spvContextCreate(SPV_ENV_VULKAN_1_0);
856111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    spv_const_binary_t binary { pCreateInfo->pCode, pCreateInfo->codeSize / sizeof(uint32_t) };
856211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    spv_diagnostic diag = nullptr;
856311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
856411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto result = spvValidate(ctx, &binary, &diag);
856511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (result != SPV_SUCCESS) {
856611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= log_msg(my_data->report_data,
856711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             result == SPV_WARNING ? VK_DEBUG_REPORT_WARNING_BIT_EXT : VK_DEBUG_REPORT_ERROR_BIT_EXT,
856811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             VkDebugReportObjectTypeEXT(0), 0,
856911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             __LINE__, SHADER_CHECKER_INCONSISTENT_SPIRV, "SC", "SPIR-V module not valid: %s",
857011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             diag && diag->error ? diag->error : "(no error text)");
857111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
857211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
857311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    spvDiagnosticDestroy(diag);
857411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    spvContextDestroy(ctx);
857511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
857611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (skip_call)
857711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return VK_ERROR_VALIDATION_FAILED_EXT;
857811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
857911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult res = my_data->device_dispatch_table->CreateShaderModule(device, pCreateInfo, pAllocator, pShaderModule);
858011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
858111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (res == VK_SUCCESS) {
858211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::lock_guard<std::mutex> lock(global_lock);
858311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        my_data->shaderModuleMap[*pShaderModule] = unique_ptr<shader_module>(new shader_module(pCreateInfo));
858411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
858511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return res;
858611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
858711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
858811cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL CreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
858911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                const VkAllocationCallbacks *pAllocator,
859011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                VkRenderPass *pRenderPass) {
859111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
859211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
859311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Create DAG
859411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::vector<bool> has_self_dependency(pCreateInfo->subpassCount);
859511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::vector<DAGNode> subpass_to_node(pCreateInfo->subpassCount);
859611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    {
859711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::lock_guard<std::mutex> lock(global_lock);
859811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= CreatePassDAG(dev_data, device, pCreateInfo, subpass_to_node, has_self_dependency);
859911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Validate
860011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= ValidateLayouts(dev_data, device, pCreateInfo);
860111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (skip_call) {
860211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return VK_ERROR_VALIDATION_FAILED_EXT;
860311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
860411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
860511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = dev_data->device_dispatch_table->CreateRenderPass(device, pCreateInfo, pAllocator, pRenderPass);
860611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (VK_SUCCESS == result) {
860711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // TODOSC : Merge in tracking of renderpass from shader_checker
860811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Shadow create info and store in map
860911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        VkRenderPassCreateInfo *localRPCI = new VkRenderPassCreateInfo(*pCreateInfo);
861011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (pCreateInfo->pAttachments) {
861111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            localRPCI->pAttachments = new VkAttachmentDescription[localRPCI->attachmentCount];
861211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            memcpy((void *)localRPCI->pAttachments, pCreateInfo->pAttachments,
861311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                   localRPCI->attachmentCount * sizeof(VkAttachmentDescription));
861411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
861511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (pCreateInfo->pSubpasses) {
861611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            localRPCI->pSubpasses = new VkSubpassDescription[localRPCI->subpassCount];
861711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            memcpy((void *)localRPCI->pSubpasses, pCreateInfo->pSubpasses, localRPCI->subpassCount * sizeof(VkSubpassDescription));
861811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
861911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (uint32_t i = 0; i < localRPCI->subpassCount; i++) {
862011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                VkSubpassDescription *subpass = (VkSubpassDescription *)&localRPCI->pSubpasses[i];
862111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                const uint32_t attachmentCount = subpass->inputAttachmentCount +
862211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                 subpass->colorAttachmentCount * (1 + (subpass->pResolveAttachments ? 1 : 0)) +
862311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                 ((subpass->pDepthStencilAttachment) ? 1 : 0) + subpass->preserveAttachmentCount;
862411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                VkAttachmentReference *attachments = new VkAttachmentReference[attachmentCount];
862511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
862611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                memcpy(attachments, subpass->pInputAttachments, sizeof(attachments[0]) * subpass->inputAttachmentCount);
862711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                subpass->pInputAttachments = attachments;
862811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                attachments += subpass->inputAttachmentCount;
862911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
863011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                memcpy(attachments, subpass->pColorAttachments, sizeof(attachments[0]) * subpass->colorAttachmentCount);
863111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                subpass->pColorAttachments = attachments;
863211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                attachments += subpass->colorAttachmentCount;
863311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
863411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (subpass->pResolveAttachments) {
863511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    memcpy(attachments, subpass->pResolveAttachments, sizeof(attachments[0]) * subpass->colorAttachmentCount);
863611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    subpass->pResolveAttachments = attachments;
863711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    attachments += subpass->colorAttachmentCount;
863811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
863911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
864011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (subpass->pDepthStencilAttachment) {
864111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    memcpy(attachments, subpass->pDepthStencilAttachment, sizeof(attachments[0]) * 1);
864211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    subpass->pDepthStencilAttachment = attachments;
864311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    attachments += 1;
864411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
864511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
864611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                memcpy(attachments, subpass->pPreserveAttachments, sizeof(attachments[0]) * subpass->preserveAttachmentCount);
864711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                subpass->pPreserveAttachments = &attachments->attachment;
864811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
864911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
865011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (pCreateInfo->pDependencies) {
865111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            localRPCI->pDependencies = new VkSubpassDependency[localRPCI->dependencyCount];
865211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            memcpy((void *)localRPCI->pDependencies, pCreateInfo->pDependencies,
865311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                   localRPCI->dependencyCount * sizeof(VkSubpassDependency));
865411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
865511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
865611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto render_pass = new RENDER_PASS_NODE(localRPCI);
865711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        render_pass->renderPass = *pRenderPass;
865811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        render_pass->hasSelfDependency = has_self_dependency;
865911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        render_pass->subpassToNode = subpass_to_node;
866011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#if MTMERGESOURCE
866111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // MTMTODO : Merge with code from above to eliminate duplication
866211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
866311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            VkAttachmentDescription desc = pCreateInfo->pAttachments[i];
866411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            MT_PASS_ATTACHMENT_INFO pass_info;
866511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pass_info.load_op = desc.loadOp;
866611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pass_info.store_op = desc.storeOp;
866711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pass_info.attachment = i;
866811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            render_pass->attachments.push_back(pass_info);
866911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
867011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // TODO: Maybe fill list and then copy instead of locking
867111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::unordered_map<uint32_t, bool> &attachment_first_read = render_pass->attachment_first_read;
867211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::unordered_map<uint32_t, VkImageLayout> &attachment_first_layout =
867311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            render_pass->attachment_first_layout;
867411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
867511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
867611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (subpass.pipelineBindPoint != VK_PIPELINE_BIND_POINT_GRAPHICS) {
867711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
867811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                     __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
867911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                     "Pipeline bind point for subpass %d must be VK_PIPELINE_BIND_POINT_GRAPHICS.", i);
868011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
868111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (uint32_t j = 0; j < subpass.preserveAttachmentCount; ++j) {
868211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                uint32_t attachment = subpass.pPreserveAttachments[j];
868311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (attachment >= pCreateInfo->attachmentCount) {
868411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
868511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
868611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         "Preserve attachment %d cannot be greater than the total number of attachments %d.",
868711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         attachment, pCreateInfo->attachmentCount);
868811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
868911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
869011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
869111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                uint32_t attachment;
869211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (subpass.pResolveAttachments) {
869311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    attachment = subpass.pResolveAttachments[j].attachment;
869411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    if (attachment >= pCreateInfo->attachmentCount && attachment != VK_ATTACHMENT_UNUSED) {
869511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
869611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                             __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
869711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                             "Color attachment %d cannot be greater than the total number of attachments %d.",
869811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                             attachment, pCreateInfo->attachmentCount);
869911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        continue;
870011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    }
870111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
870211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                attachment = subpass.pColorAttachments[j].attachment;
870311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (attachment >= pCreateInfo->attachmentCount) {
870411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
870511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
870611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         "Color attachment %d cannot be greater than the total number of attachments %d.",
870711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         attachment, pCreateInfo->attachmentCount);
870811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    continue;
870911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
871011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (attachment_first_read.count(attachment))
871111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    continue;
871211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                attachment_first_read.insert(std::make_pair(attachment, false));
871311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                attachment_first_layout.insert(std::make_pair(attachment, subpass.pColorAttachments[j].layout));
871411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
871511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
871611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                uint32_t attachment = subpass.pDepthStencilAttachment->attachment;
871711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (attachment >= pCreateInfo->attachmentCount) {
871811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
871911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
872011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         "Depth stencil attachment %d cannot be greater than the total number of attachments %d.",
872111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         attachment, pCreateInfo->attachmentCount);
872211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    continue;
872311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
872411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (attachment_first_read.count(attachment))
872511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    continue;
872611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                attachment_first_read.insert(std::make_pair(attachment, false));
872711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                attachment_first_layout.insert(std::make_pair(attachment, subpass.pDepthStencilAttachment->layout));
872811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
872911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
873011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                uint32_t attachment = subpass.pInputAttachments[j].attachment;
873111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (attachment >= pCreateInfo->attachmentCount) {
873211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
873311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
873411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         "Input attachment %d cannot be greater than the total number of attachments %d.",
873511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         attachment, pCreateInfo->attachmentCount);
873611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    continue;
873711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
873811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (attachment_first_read.count(attachment))
873911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    continue;
874011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                attachment_first_read.insert(std::make_pair(attachment, true));
874111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                attachment_first_layout.insert(std::make_pair(attachment, subpass.pInputAttachments[j].layout));
874211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
874311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
874411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#endif
874511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {
874611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            std::lock_guard<std::mutex> lock(global_lock);
874711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            dev_data->renderPassMap[*pRenderPass] = render_pass;
874811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
874911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
875011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
875111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
875211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Free the renderpass shadow
875311cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void deleteRenderPasses(layer_data *my_data) {
875411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (my_data->renderPassMap.size() <= 0)
875511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return;
875611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto ii = my_data->renderPassMap.begin(); ii != my_data->renderPassMap.end(); ++ii) {
875711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        const VkRenderPassCreateInfo *pRenderPassInfo = (*ii).second->pCreateInfo;
875811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        delete[] pRenderPassInfo->pAttachments;
875911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (pRenderPassInfo->pSubpasses) {
876011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (uint32_t i = 0; i < pRenderPassInfo->subpassCount; ++i) {
876111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                // Attachements are all allocated in a block, so just need to
876211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                //  find the first non-null one to delete
876311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (pRenderPassInfo->pSubpasses[i].pInputAttachments) {
876411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    delete[] pRenderPassInfo->pSubpasses[i].pInputAttachments;
876511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                } else if (pRenderPassInfo->pSubpasses[i].pColorAttachments) {
876611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    delete[] pRenderPassInfo->pSubpasses[i].pColorAttachments;
876711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                } else if (pRenderPassInfo->pSubpasses[i].pResolveAttachments) {
876811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    delete[] pRenderPassInfo->pSubpasses[i].pResolveAttachments;
876911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                } else if (pRenderPassInfo->pSubpasses[i].pPreserveAttachments) {
877011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    delete[] pRenderPassInfo->pSubpasses[i].pPreserveAttachments;
877111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
877211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
877311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            delete[] pRenderPassInfo->pSubpasses;
877411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
877511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        delete[] pRenderPassInfo->pDependencies;
877611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        delete pRenderPassInfo;
877711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        delete (*ii).second;
877811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
877911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    my_data->renderPassMap.clear();
878011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
878111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
878211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool VerifyFramebufferAndRenderPassLayouts(layer_data *dev_data, GLOBAL_CB_NODE *pCB, const VkRenderPassBeginInfo *pRenderPassBegin) {
878311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
878411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    const VkRenderPassCreateInfo *pRenderPassInfo = dev_data->renderPassMap[pRenderPassBegin->renderPass]->pCreateInfo;
878511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    const VkFramebufferCreateInfo framebufferInfo = dev_data->frameBufferMap[pRenderPassBegin->framebuffer].createInfo;
878611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pRenderPassInfo->attachmentCount != framebufferInfo.attachmentCount) {
878711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
878811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             DRAWSTATE_INVALID_RENDERPASS, "DS", "You cannot start a render pass using a framebuffer "
878911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                 "with a different number of attachments.");
879011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
879111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < pRenderPassInfo->attachmentCount; ++i) {
879211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        const VkImageView &image_view = framebufferInfo.pAttachments[i];
879311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto image_data = dev_data->imageViewMap.find(image_view);
879411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        assert(image_data != dev_data->imageViewMap.end());
879511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        const VkImage &image = image_data->second.image;
879611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        const VkImageSubresourceRange &subRange = image_data->second.subresourceRange;
879711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        IMAGE_CMD_BUF_LAYOUT_NODE newNode = {pRenderPassInfo->pAttachments[i].initialLayout,
879811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                             pRenderPassInfo->pAttachments[i].initialLayout};
879911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // TODO: Do not iterate over every possibility - consolidate where possible
880011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t j = 0; j < subRange.levelCount; j++) {
880111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            uint32_t level = subRange.baseMipLevel + j;
880211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (uint32_t k = 0; k < subRange.layerCount; k++) {
880311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                uint32_t layer = subRange.baseArrayLayer + k;
880411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                VkImageSubresource sub = {subRange.aspectMask, level, layer};
880511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                IMAGE_CMD_BUF_LAYOUT_NODE node;
880611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (!FindLayout(pCB, image, sub, node)) {
880711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    SetLayout(pCB, image, sub, newNode);
880811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    continue;
880911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
881011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (newNode.layout != node.layout) {
881111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skip_call |=
881211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
881311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                DRAWSTATE_INVALID_RENDERPASS, "DS", "You cannot start a render pass using attachment %i "
881411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                    "where the "
881511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                    "initial layout is %s and the layout of the attachment at the "
881611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                    "start of the render pass is %s. The layouts must match.",
881711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                i, string_VkImageLayout(newNode.layout), string_VkImageLayout(node.layout));
881811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
881911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
882011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
882111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
882211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skip_call;
882311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
882411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
882511cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void TransitionSubpassLayouts(layer_data *dev_data, GLOBAL_CB_NODE *pCB, const VkRenderPassBeginInfo *pRenderPassBegin,
882611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                     const int subpass_index) {
882711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto renderPass = getRenderPass(dev_data, pRenderPassBegin->renderPass);
882811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!renderPass)
882911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return;
883011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
883111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto framebuffer = getFramebuffer(dev_data, pRenderPassBegin->framebuffer);
883211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!framebuffer)
883311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return;
883411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
883511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    const VkFramebufferCreateInfo &framebufferInfo = framebuffer->createInfo;
883611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    const VkSubpassDescription &subpass = renderPass->pCreateInfo->pSubpasses[subpass_index];
883711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
883811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        const VkImageView &image_view = framebufferInfo.pAttachments[subpass.pInputAttachments[j].attachment];
883911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        SetLayout(dev_data, pCB, image_view, subpass.pInputAttachments[j].layout);
884011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
884111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
884211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        const VkImageView &image_view = framebufferInfo.pAttachments[subpass.pColorAttachments[j].attachment];
884311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        SetLayout(dev_data, pCB, image_view, subpass.pColorAttachments[j].layout);
884411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
884511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if ((subpass.pDepthStencilAttachment != NULL) && (subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED)) {
884611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        const VkImageView &image_view = framebufferInfo.pAttachments[subpass.pDepthStencilAttachment->attachment];
884711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        SetLayout(dev_data, pCB, image_view, subpass.pDepthStencilAttachment->layout);
884811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
884911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
885011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
885111cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validatePrimaryCommandBuffer(const layer_data *my_data, const GLOBAL_CB_NODE *pCB, const std::string &cmd_name) {
885211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
885311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
885411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
885511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", "Cannot execute command %s on a secondary command buffer.",
885611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             cmd_name.c_str());
885711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
885811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skip_call;
885911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
886011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
886111cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void TransitionFinalSubpassLayouts(layer_data *dev_data, GLOBAL_CB_NODE *pCB, const VkRenderPassBeginInfo *pRenderPassBegin) {
886211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto renderPass = getRenderPass(dev_data, pRenderPassBegin->renderPass);
886311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!renderPass)
886411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return;
886511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
886611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    const VkRenderPassCreateInfo *pRenderPassInfo = renderPass->pCreateInfo;
886711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto framebuffer = getFramebuffer(dev_data, pRenderPassBegin->framebuffer);
886811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!framebuffer)
886911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return;
887011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
887111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < pRenderPassInfo->attachmentCount; ++i) {
887211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        const VkImageView &image_view = framebuffer->createInfo.pAttachments[i];
887311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        SetLayout(dev_data, pCB, image_view, pRenderPassInfo->pAttachments[i].finalLayout);
887411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
887511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
887611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
887711cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool VerifyRenderAreaBounds(const layer_data *my_data, const VkRenderPassBeginInfo *pRenderPassBegin) {
887811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
887911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    const VkFramebufferCreateInfo *pFramebufferInfo = &my_data->frameBufferMap.at(pRenderPassBegin->framebuffer).createInfo;
888011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pRenderPassBegin->renderArea.offset.x < 0 ||
888111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        (pRenderPassBegin->renderArea.offset.x + pRenderPassBegin->renderArea.extent.width) > pFramebufferInfo->width ||
888211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pRenderPassBegin->renderArea.offset.y < 0 ||
888311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        (pRenderPassBegin->renderArea.offset.y + pRenderPassBegin->renderArea.extent.height) > pFramebufferInfo->height) {
888411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= static_cast<bool>(log_msg(
888511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
888611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            DRAWSTATE_INVALID_RENDER_AREA, "CORE",
888711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            "Cannot execute a render pass with renderArea not within the bound of the "
888811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            "framebuffer. RenderArea: x %d, y %d, width %d, height %d. Framebuffer: width %d, "
888911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            "height %d.",
889011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pRenderPassBegin->renderArea.offset.x, pRenderPassBegin->renderArea.offset.y, pRenderPassBegin->renderArea.extent.width,
889111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pRenderPassBegin->renderArea.extent.height, pFramebufferInfo->width, pFramebufferInfo->height));
889211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
889311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skip_call;
889411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
889511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
889611cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
889711cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin, VkSubpassContents contents) {
889811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
889911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
890011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
890111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
890211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto renderPass = pRenderPassBegin ? getRenderPass(dev_data, pRenderPassBegin->renderPass) : nullptr;
890311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto framebuffer = pRenderPassBegin ? getFramebuffer(dev_data, pRenderPassBegin->framebuffer) : nullptr;
890411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
890511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (renderPass) {
890611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#if MTMERGE
890711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pCB->activeFramebuffer = pRenderPassBegin->framebuffer;
890811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (size_t i = 0; i < renderPass->attachments.size(); ++i) {
890911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                MT_FB_ATTACHMENT_INFO &fb_info = framebuffer->attachments[i];
891011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (renderPass->attachments[i].load_op == VK_ATTACHMENT_LOAD_OP_CLEAR) {
891111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    std::function<bool()> function = [=]() {
891211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        set_memory_valid(dev_data, fb_info.mem, true, fb_info.image);
891311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        return false;
891411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    };
891511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    pCB->validate_functions.push_back(function);
891611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                } else if (renderPass->attachments[i].load_op == VK_ATTACHMENT_LOAD_OP_DONT_CARE) {
891711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    std::function<bool()> function = [=]() {
891811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        set_memory_valid(dev_data, fb_info.mem, false, fb_info.image);
891911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        return false;
892011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    };
892111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    pCB->validate_functions.push_back(function);
892211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                } else if (renderPass->attachments[i].load_op == VK_ATTACHMENT_LOAD_OP_LOAD) {
892311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    std::function<bool()> function = [=]() {
892411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        return validate_memory_is_valid(dev_data, fb_info.mem, "vkCmdBeginRenderPass()", fb_info.image);
892511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    };
892611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    pCB->validate_functions.push_back(function);
892711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
892811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (renderPass->attachment_first_read[renderPass->attachments[i].attachment]) {
892911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    std::function<bool()> function = [=]() {
893011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        return validate_memory_is_valid(dev_data, fb_info.mem, "vkCmdBeginRenderPass()", fb_info.image);
893111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    };
893211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    pCB->validate_functions.push_back(function);
893311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
893411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
893511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#endif
893611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= VerifyRenderAreaBounds(dev_data, pRenderPassBegin);
893711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= VerifyFramebufferAndRenderPassLayouts(dev_data, pCB, pRenderPassBegin);
893811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= insideRenderPass(dev_data, pCB, "vkCmdBeginRenderPass");
893911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (renderPass) {
894011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skipCall |= ValidateDependencies(dev_data, framebuffer, renderPass);
894111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
894211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pCB->activeRenderPass = renderPass;
894311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdBeginRenderPass");
894411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= addCmd(dev_data, pCB, CMD_BEGINRENDERPASS, "vkCmdBeginRenderPass()");
894511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // This is a shallow copy as that is all that is needed for now
894611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pCB->activeRenderPassBeginInfo = *pRenderPassBegin;
894711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pCB->activeSubpass = 0;
894811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pCB->activeSubpassContents = contents;
894911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pCB->framebuffers.insert(pRenderPassBegin->framebuffer);
895011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // Connect this framebuffer to this cmdBuffer
895111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            framebuffer->referencingCmdBuffers.insert(pCB->commandBuffer);
895211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        } else {
895311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |=
895411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
895511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            DRAWSTATE_INVALID_RENDERPASS, "DS", "You cannot use a NULL RenderPass object in vkCmdBeginRenderPass()");
895611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
895711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
895811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
895911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall) {
896011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdBeginRenderPass(commandBuffer, pRenderPassBegin, contents);
896111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
896211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
896311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
896411cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL CmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents) {
896511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
896611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
896711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
896811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
896911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
897011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdNextSubpass");
897111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= addCmd(dev_data, pCB, CMD_NEXTSUBPASS, "vkCmdNextSubpass()");
897211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->activeSubpass++;
897311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->activeSubpassContents = contents;
897411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        TransitionSubpassLayouts(dev_data, pCB, &pCB->activeRenderPassBeginInfo, pCB->activeSubpass);
897511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdNextSubpass");
897611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
897711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
897811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
897911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdNextSubpass(commandBuffer, contents);
898011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
898111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
898211cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL CmdEndRenderPass(VkCommandBuffer commandBuffer) {
898311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
898411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
898511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
898611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto pCB = getCBNode(dev_data, commandBuffer);
898711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
898811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        RENDER_PASS_NODE* pRPNode = pCB->activeRenderPass;
898911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto framebuffer = getFramebuffer(dev_data, pCB->activeFramebuffer);
899011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (pRPNode) {
899111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (size_t i = 0; i < pRPNode->attachments.size(); ++i) {
899211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                MT_FB_ATTACHMENT_INFO &fb_info = framebuffer->attachments[i];
899311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (pRPNode->attachments[i].store_op == VK_ATTACHMENT_STORE_OP_STORE) {
899411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    std::function<bool()> function = [=]() {
899511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        set_memory_valid(dev_data, fb_info.mem, true, fb_info.image);
899611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        return false;
899711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    };
899811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    pCB->validate_functions.push_back(function);
899911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                } else if (pRPNode->attachments[i].store_op == VK_ATTACHMENT_STORE_OP_DONT_CARE) {
900011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    std::function<bool()> function = [=]() {
900111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        set_memory_valid(dev_data, fb_info.mem, false, fb_info.image);
900211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        return false;
900311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    };
900411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    pCB->validate_functions.push_back(function);
900511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
900611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
900711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
900811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdEndRenderpass");
900911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdEndRenderPass");
901011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= addCmd(dev_data, pCB, CMD_ENDRENDERPASS, "vkCmdEndRenderPass()");
901111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        TransitionFinalSubpassLayouts(dev_data, pCB, &pCB->activeRenderPassBeginInfo);
901211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->activeRenderPass = nullptr;
901311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->activeSubpass = 0;
901411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pCB->activeFramebuffer = VK_NULL_HANDLE;
901511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
901611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
901711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
901811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdEndRenderPass(commandBuffer);
901911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
902011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
902111cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool logInvalidAttachmentMessage(layer_data *dev_data, VkCommandBuffer secondaryBuffer, RENDER_PASS_NODE const *secondaryPass,
902211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        RENDER_PASS_NODE const *primaryPass, uint32_t primaryAttach, uint32_t secondaryAttach,
902311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        const char *msg) {
902411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
902511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                   DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
902611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                   "vkCmdExecuteCommands() called w/ invalid Cmd Buffer 0x%p which has a render pass 0x%" PRIx64
902711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                   " that is not compatible with the current render pass 0x%" PRIx64 "."
902811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                   "Attachment %" PRIu32 " is not compatible with %" PRIu32 ". %s",
902911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                   (void *)secondaryBuffer, (uint64_t)(secondaryPass->renderPass), (uint64_t)(primaryPass->renderPass), primaryAttach, secondaryAttach,
903011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                   msg);
903111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
903211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
903311cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validateAttachmentCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer, RENDER_PASS_NODE const *primaryPass,
903411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            uint32_t primaryAttach, VkCommandBuffer secondaryBuffer, RENDER_PASS_NODE const *secondaryPass,
903511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            uint32_t secondaryAttach, bool is_multi) {
903611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
903711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (primaryPass->pCreateInfo->attachmentCount <= primaryAttach) {
903811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        primaryAttach = VK_ATTACHMENT_UNUSED;
903911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
904011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (secondaryPass->pCreateInfo->attachmentCount <= secondaryAttach) {
904111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        secondaryAttach = VK_ATTACHMENT_UNUSED;
904211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
904311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (primaryAttach == VK_ATTACHMENT_UNUSED && secondaryAttach == VK_ATTACHMENT_UNUSED) {
904411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return skip_call;
904511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
904611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (primaryAttach == VK_ATTACHMENT_UNUSED) {
904711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, secondaryPass, primaryPass, primaryAttach,
904811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                 secondaryAttach, "The first is unused while the second is not.");
904911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return skip_call;
905011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
905111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (secondaryAttach == VK_ATTACHMENT_UNUSED) {
905211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, secondaryPass, primaryPass, primaryAttach,
905311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                 secondaryAttach, "The second is unused while the first is not.");
905411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return skip_call;
905511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
905611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (primaryPass->pCreateInfo->pAttachments[primaryAttach].format !=
905711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        secondaryPass->pCreateInfo->pAttachments[secondaryAttach].format) {
905811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, secondaryPass, primaryPass, primaryAttach,
905911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                 secondaryAttach, "They have different formats.");
906011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
906111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (primaryPass->pCreateInfo->pAttachments[primaryAttach].samples !=
906211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        secondaryPass->pCreateInfo->pAttachments[secondaryAttach].samples) {
906311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, secondaryPass, primaryPass, primaryAttach,
906411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                 secondaryAttach, "They have different samples.");
906511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
906611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (is_multi &&
906711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        primaryPass->pCreateInfo->pAttachments[primaryAttach].flags !=
906811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            secondaryPass->pCreateInfo->pAttachments[secondaryAttach].flags) {
906911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, secondaryPass, primaryPass, primaryAttach,
907011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                 secondaryAttach, "They have different flags.");
907111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
907211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skip_call;
907311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
907411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
907511cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validateSubpassCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer, RENDER_PASS_NODE const *primaryPass,
907611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         VkCommandBuffer secondaryBuffer, RENDER_PASS_NODE const *secondaryPass, const int subpass,
907711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         bool is_multi) {
907811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
907911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    const VkSubpassDescription &primary_desc = primaryPass->pCreateInfo->pSubpasses[subpass];
908011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    const VkSubpassDescription &secondary_desc = secondaryPass->pCreateInfo->pSubpasses[subpass];
908111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    uint32_t maxInputAttachmentCount = std::max(primary_desc.inputAttachmentCount, secondary_desc.inputAttachmentCount);
908211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < maxInputAttachmentCount; ++i) {
908311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        uint32_t primary_input_attach = VK_ATTACHMENT_UNUSED, secondary_input_attach = VK_ATTACHMENT_UNUSED;
908411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (i < primary_desc.inputAttachmentCount) {
908511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            primary_input_attach = primary_desc.pInputAttachments[i].attachment;
908611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
908711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (i < secondary_desc.inputAttachmentCount) {
908811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            secondary_input_attach = secondary_desc.pInputAttachments[i].attachment;
908911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
909011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPass, primary_input_attach, secondaryBuffer,
909111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                     secondaryPass, secondary_input_attach, is_multi);
909211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
909311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    uint32_t maxColorAttachmentCount = std::max(primary_desc.colorAttachmentCount, secondary_desc.colorAttachmentCount);
909411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < maxColorAttachmentCount; ++i) {
909511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        uint32_t primary_color_attach = VK_ATTACHMENT_UNUSED, secondary_color_attach = VK_ATTACHMENT_UNUSED;
909611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (i < primary_desc.colorAttachmentCount) {
909711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            primary_color_attach = primary_desc.pColorAttachments[i].attachment;
909811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
909911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (i < secondary_desc.colorAttachmentCount) {
910011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            secondary_color_attach = secondary_desc.pColorAttachments[i].attachment;
910111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
910211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPass, primary_color_attach, secondaryBuffer,
910311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                     secondaryPass, secondary_color_attach, is_multi);
910411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        uint32_t primary_resolve_attach = VK_ATTACHMENT_UNUSED, secondary_resolve_attach = VK_ATTACHMENT_UNUSED;
910511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (i < primary_desc.colorAttachmentCount && primary_desc.pResolveAttachments) {
910611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            primary_resolve_attach = primary_desc.pResolveAttachments[i].attachment;
910711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
910811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (i < secondary_desc.colorAttachmentCount && secondary_desc.pResolveAttachments) {
910911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            secondary_resolve_attach = secondary_desc.pResolveAttachments[i].attachment;
911011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
911111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPass, primary_resolve_attach, secondaryBuffer,
911211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                     secondaryPass, secondary_resolve_attach, is_multi);
911311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
911411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    uint32_t primary_depthstencil_attach = VK_ATTACHMENT_UNUSED, secondary_depthstencil_attach = VK_ATTACHMENT_UNUSED;
911511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (primary_desc.pDepthStencilAttachment) {
911611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        primary_depthstencil_attach = primary_desc.pDepthStencilAttachment[0].attachment;
911711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
911811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (secondary_desc.pDepthStencilAttachment) {
911911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        secondary_depthstencil_attach = secondary_desc.pDepthStencilAttachment[0].attachment;
912011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
912111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPass, primary_depthstencil_attach, secondaryBuffer,
912211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                 secondaryPass, secondary_depthstencil_attach, is_multi);
912311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skip_call;
912411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
912511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
912611cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validateRenderPassCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer, VkRenderPass primaryPass,
912711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            VkCommandBuffer secondaryBuffer, VkRenderPass secondaryPass) {
912811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
912911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Early exit if renderPass objects are identical (and therefore compatible)
913011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (primaryPass == secondaryPass)
913111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return skip_call;
913211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto primary_render_pass = getRenderPass(dev_data, primaryPass);
913311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto secondary_render_pass = getRenderPass(dev_data, secondaryPass);
913411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!primary_render_pass) {
913511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |=
913611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
913711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
913811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    "vkCmdExecuteCommands() called w/ invalid current Cmd Buffer 0x%p which has invalid render pass 0x%" PRIx64 ".",
913911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    (void *)primaryBuffer, (uint64_t)(primaryPass));
914011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return skip_call;
914111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
914211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!secondary_render_pass) {
914311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |=
914411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
914511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
914611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    "vkCmdExecuteCommands() called w/ invalid secondary Cmd Buffer 0x%p which has invalid render pass 0x%" PRIx64 ".",
914711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    (void *)secondaryBuffer, (uint64_t)(secondaryPass));
914811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return skip_call;
914911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
915011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (primary_render_pass->pCreateInfo->subpassCount != secondary_render_pass->pCreateInfo->subpassCount) {
915111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
915211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
915311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             "vkCmdExecuteCommands() called w/ invalid Cmd Buffer 0x%p which has a render pass 0x%" PRIx64
915411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             " that is not compatible with the current render pass 0x%" PRIx64 "."
915511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             "They have a different number of subpasses.",
915611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             (void *)secondaryBuffer, (uint64_t)(secondaryPass), (uint64_t)(primaryPass));
915711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return skip_call;
915811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
915911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto subpassCount = primary_render_pass->pCreateInfo->subpassCount;
916011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < subpassCount; ++i) {
916111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= validateSubpassCompatibility(dev_data, primaryBuffer, primary_render_pass, secondaryBuffer,
916211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                  secondary_render_pass, i, subpassCount > 1);
916311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
916411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skip_call;
916511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
916611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
916711cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validateFramebuffer(layer_data *dev_data, VkCommandBuffer primaryBuffer, const GLOBAL_CB_NODE *pCB,
916811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                VkCommandBuffer secondaryBuffer, const GLOBAL_CB_NODE *pSubCB) {
916911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
917011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!pSubCB->beginInfo.pInheritanceInfo) {
917111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return skip_call;
917211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
917311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkFramebuffer primary_fb = pCB->activeFramebuffer;
917411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkFramebuffer secondary_fb = pSubCB->beginInfo.pInheritanceInfo->framebuffer;
917511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (secondary_fb != VK_NULL_HANDLE) {
917611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (primary_fb != secondary_fb) {
917711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
917811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
917911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 "vkCmdExecuteCommands() called w/ invalid Cmd Buffer 0x%p which has a framebuffer 0x%" PRIx64
918011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 " that is not compatible with the current framebuffer 0x%" PRIx64 ".",
918111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 (void *)secondaryBuffer, (uint64_t)(secondary_fb), (uint64_t)(primary_fb));
918211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
918311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto fb = getFramebuffer(dev_data, secondary_fb);
918411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!fb) {
918511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |=
918611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
918711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS", "vkCmdExecuteCommands() called w/ invalid Cmd Buffer 0x%p "
918811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                          "which has invalid framebuffer 0x%" PRIx64 ".",
918911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        (void *)secondaryBuffer, (uint64_t)(secondary_fb));
919011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return skip_call;
919111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
919211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skip_call |= validateRenderPassCompatibility(dev_data, secondaryBuffer, fb->createInfo.renderPass,
919311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                     secondaryBuffer, pSubCB->beginInfo.pInheritanceInfo->renderPass);
919411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
919511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skip_call;
919611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
919711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
919811cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validateSecondaryCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB, GLOBAL_CB_NODE *pSubCB) {
919911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
920011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    unordered_set<int> activeTypes;
920111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto queryObject : pCB->activeQueries) {
920211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto queryPoolData = dev_data->queryPoolMap.find(queryObject.pool);
920311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (queryPoolData != dev_data->queryPoolMap.end()) {
920411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (queryPoolData->second.createInfo.queryType == VK_QUERY_TYPE_PIPELINE_STATISTICS &&
920511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pSubCB->beginInfo.pInheritanceInfo) {
920611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                VkQueryPipelineStatisticFlags cmdBufStatistics = pSubCB->beginInfo.pInheritanceInfo->pipelineStatistics;
920711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if ((cmdBufStatistics & queryPoolData->second.createInfo.pipelineStatistics) != cmdBufStatistics) {
920811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skipCall |= log_msg(
920911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
921011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
921111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "vkCmdExecuteCommands() called w/ invalid Cmd Buffer 0x%p "
921211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "which has invalid active query pool 0x%" PRIx64 ". Pipeline statistics is being queried so the command "
921311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "buffer must have all bits set on the queryPool.",
921411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        reinterpret_cast<void *>(pCB->commandBuffer), reinterpret_cast<const uint64_t &>(queryPoolData->first));
921511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
921611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
921711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            activeTypes.insert(queryPoolData->second.createInfo.queryType);
921811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
921911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
922011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto queryObject : pSubCB->startedQueries) {
922111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto queryPoolData = dev_data->queryPoolMap.find(queryObject.pool);
922211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (queryPoolData != dev_data->queryPoolMap.end() && activeTypes.count(queryPoolData->second.createInfo.queryType)) {
922311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |=
922411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
922511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
922611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "vkCmdExecuteCommands() called w/ invalid Cmd Buffer 0x%p "
922711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "which has invalid active query pool 0x%" PRIx64 "of type %d but a query of that type has been started on "
922811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "secondary Cmd Buffer 0x%p.",
922911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        reinterpret_cast<void *>(pCB->commandBuffer), reinterpret_cast<const uint64_t &>(queryPoolData->first),
923011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        queryPoolData->second.createInfo.queryType, reinterpret_cast<void *>(pSubCB->commandBuffer));
923111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
923211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
923311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skipCall;
923411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
923511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
923611cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
923711cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBuffersCount, const VkCommandBuffer *pCommandBuffers) {
923811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
923911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
924011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
924111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
924211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pCB) {
924311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        GLOBAL_CB_NODE *pSubCB = NULL;
924411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t i = 0; i < commandBuffersCount; i++) {
924511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pSubCB = getCBNode(dev_data, pCommandBuffers[i]);
924611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (!pSubCB) {
924711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skipCall |=
924811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
924911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
925011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "vkCmdExecuteCommands() called w/ invalid Cmd Buffer 0x%p in element %u of pCommandBuffers array.",
925111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            (void *)pCommandBuffers[i], i);
925211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            } else if (VK_COMMAND_BUFFER_LEVEL_PRIMARY == pSubCB->createInfo.level) {
925311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
925411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    __LINE__, DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
925511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    "vkCmdExecuteCommands() called w/ Primary Cmd Buffer 0x%p in element %u of pCommandBuffers "
925611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    "array. All cmd buffers in pCommandBuffers array must be secondary.",
925711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    (void *)pCommandBuffers[i], i);
925811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            } else if (pCB->activeRenderPass) { // Secondary CB w/i RenderPass must have *CONTINUE_BIT set
925911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (!(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
926011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skipCall |= log_msg(
926111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
926211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        (uint64_t)pCommandBuffers[i], __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS",
926311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "vkCmdExecuteCommands(): Secondary Command Buffer (0x%p) executed within render pass (0x%" PRIxLEAST64
926411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        ") must have had vkBeginCommandBuffer() called w/ VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT set.",
926511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        (void *)pCommandBuffers[i], (uint64_t)pCB->activeRenderPass->renderPass);
926611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                } else {
926711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    // Make sure render pass is compatible with parent command buffer pass if has continue
926811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skipCall |= validateRenderPassCompatibility(dev_data, commandBuffer, pCB->activeRenderPass->renderPass, pCommandBuffers[i],
926911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                pSubCB->beginInfo.pInheritanceInfo->renderPass);
927011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skipCall |= validateFramebuffer(dev_data, commandBuffer, pCB, pCommandBuffers[i], pSubCB);
927111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
927211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                string errorString = "";
927311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (!verify_renderpass_compatibility(dev_data, pCB->activeRenderPass->renderPass,
927411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                     pSubCB->beginInfo.pInheritanceInfo->renderPass, errorString)) {
927511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skipCall |= log_msg(
927611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
927711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        (uint64_t)pCommandBuffers[i], __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE, "DS",
927811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "vkCmdExecuteCommands(): Secondary Command Buffer (0x%p) w/ render pass (0x%" PRIxLEAST64
927911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        ") is incompatible w/ primary command buffer (0x%p) w/ render pass (0x%" PRIxLEAST64 ") due to: %s",
928011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        (void *)pCommandBuffers[i], (uint64_t)pSubCB->beginInfo.pInheritanceInfo->renderPass, (void *)commandBuffer,
928111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        (uint64_t)pCB->activeRenderPass->renderPass, errorString.c_str());
928211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
928311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                //  If framebuffer for secondary CB is not NULL, then it must match FB from vkCmdBeginRenderPass()
928411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                //   that this CB will be executed in AND framebuffer must have been created w/ RP compatible w/ renderpass
928511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (pSubCB->beginInfo.pInheritanceInfo->framebuffer) {
928611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    if (pSubCB->beginInfo.pInheritanceInfo->framebuffer != pCB->activeRenderPassBeginInfo.framebuffer) {
928711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        skipCall |= log_msg(
928811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
928911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            (uint64_t)pCommandBuffers[i], __LINE__, DRAWSTATE_FRAMEBUFFER_INCOMPATIBLE, "DS",
929011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "vkCmdExecuteCommands(): Secondary Command Buffer (0x%p) references framebuffer (0x%" PRIxLEAST64
929111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            ") that does not match framebuffer (0x%" PRIxLEAST64 ") in active renderpass (0x%" PRIxLEAST64 ").",
929211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            (void *)pCommandBuffers[i], (uint64_t)pSubCB->beginInfo.pInheritanceInfo->framebuffer,
929311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            (uint64_t)pCB->activeRenderPassBeginInfo.framebuffer, (uint64_t)pCB->activeRenderPass->renderPass);
929411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    }
929511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
929611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
929711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // TODO(mlentine): Move more logic into this method
929811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= validateSecondaryCommandBufferState(dev_data, pCB, pSubCB);
929911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |= validateCommandBufferState(dev_data, pSubCB);
930011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // Secondary cmdBuffers are considered pending execution starting w/
930111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // being recorded
930211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (!(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
930311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (dev_data->globalInFlightCmdBuffers.find(pSubCB->commandBuffer) != dev_data->globalInFlightCmdBuffers.end()) {
930411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skipCall |= log_msg(
930511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
930611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        (uint64_t)(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_CB_SIMULTANEOUS_USE, "DS",
930711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "Attempt to simultaneously execute CB 0x%" PRIxLEAST64 " w/o VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT "
930811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "set!",
930911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        (uint64_t)(pCB->commandBuffer));
931011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
931111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT) {
931211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    // Warn that non-simultaneous secondary cmd buffer renders primary non-simultaneous
931311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skipCall |= log_msg(
931411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
931511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        (uint64_t)(pCommandBuffers[i]), __LINE__, DRAWSTATE_INVALID_CB_SIMULTANEOUS_USE, "DS",
931611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "vkCmdExecuteCommands(): Secondary Command Buffer (0x%" PRIxLEAST64
931711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        ") does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set and will cause primary command buffer "
931811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "(0x%" PRIxLEAST64 ") to be treated as if it does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT "
931911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                          "set, even though it does.",
932011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        (uint64_t)(pCommandBuffers[i]), (uint64_t)(pCB->commandBuffer));
932111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    pCB->beginInfo.flags &= ~VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
932211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
932311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
932411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (!pCB->activeQueries.empty() && !dev_data->phys_dev_properties.features.inheritedQueries) {
932511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skipCall |=
932611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
932711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            reinterpret_cast<uint64_t>(pCommandBuffers[i]), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
932811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "vkCmdExecuteCommands(): Secondary Command Buffer "
932911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "(0x%" PRIxLEAST64 ") cannot be submitted with a query in "
933011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "flight and inherited queries not "
933111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            "supported on this device.",
933211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            reinterpret_cast<uint64_t>(pCommandBuffers[i]));
933311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
933411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pSubCB->primaryCommandBuffer = pCB->commandBuffer;
933511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            pCB->secondaryCommandBuffers.insert(pSubCB->commandBuffer);
933611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            dev_data->globalInFlightCmdBuffers.insert(pSubCB->commandBuffer);
933711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
933811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdExecuteComands");
933911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall |= addCmd(dev_data, pCB, CMD_EXECUTECOMMANDS, "vkCmdExecuteComands()");
934011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
934111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
934211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
934311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->CmdExecuteCommands(commandBuffer, commandBuffersCount, pCommandBuffers);
934411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
934511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
934611cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool ValidateMapImageLayouts(VkDevice device, VkDeviceMemory mem) {
934711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
934811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
934911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto mem_data = dev_data->memObjMap.find(mem);
935011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if ((mem_data != dev_data->memObjMap.end()) && (mem_data->second.image != VK_NULL_HANDLE)) {
935111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::vector<VkImageLayout> layouts;
935211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (FindLayouts(dev_data, mem_data->second.image, layouts)) {
935311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (auto layout : layouts) {
935411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (layout != VK_IMAGE_LAYOUT_PREINITIALIZED && layout != VK_IMAGE_LAYOUT_GENERAL) {
935511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
935611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Cannot map an image with layout %s. Only "
935711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                                         "GENERAL or PREINITIALIZED are supported.",
935811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                         string_VkImageLayout(layout));
935911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
936011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
936111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
936211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
936311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skip_call;
936411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
936511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
936611cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL
936711cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertMapMemory(VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size, VkFlags flags, void **ppData) {
936811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
936911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
937011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
937111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
937211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
937311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#if MTMERGESOURCE
937411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    DEVICE_MEM_INFO *pMemObj = get_mem_obj_info(dev_data, mem);
937511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pMemObj) {
937611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        pMemObj->valid = true;
937711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if ((dev_data->phys_dev_mem_props.memoryTypes[pMemObj->allocInfo.memoryTypeIndex].propertyFlags &
937811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert             VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) {
937911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call =
938011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
938111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        (uint64_t)mem, __LINE__, MEMTRACK_INVALID_STATE, "MEM",
938211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "Mapping Memory without VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT set: mem obj 0x%" PRIxLEAST64, (uint64_t)mem);
938311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
938411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
938511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skip_call |= validateMemRange(dev_data, mem, offset, size);
938611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#endif
938711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skip_call |= ValidateMapImageLayouts(device, mem);
938811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
938911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
939011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skip_call) {
939111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        result = dev_data->device_dispatch_table->MapMemory(device, mem, offset, size, flags, ppData);
939211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (VK_SUCCESS == result) {
939311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#if MTMERGESOURCE
939411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            lock.lock();
939511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            storeMemRanges(dev_data, mem, offset, size);
939611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            initializeAndTrackMemory(dev_data, mem, size, ppData);
939711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            lock.unlock();
939811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#endif
939911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
940011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
940111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
940211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
940311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
940411cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL UnmapMemory(VkDevice device, VkDeviceMemory mem) {
940511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
940611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
940711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
940811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
940911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= deleteMemRanges(my_data, mem);
941011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
941111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall) {
941211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        my_data->device_dispatch_table->UnmapMemory(device, mem);
941311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
941411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
941511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
941611cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validateMemoryIsMapped(layer_data *my_data, const char *funcName, uint32_t memRangeCount,
941711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                   const VkMappedMemoryRange *pMemRanges) {
941811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
941911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < memRangeCount; ++i) {
942011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto mem_element = my_data->memObjMap.find(pMemRanges[i].memory);
942111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (mem_element != my_data->memObjMap.end()) {
942211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (mem_element->second.memRange.offset > pMemRanges[i].offset) {
942311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skipCall |= log_msg(
942411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
942511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    (uint64_t)pMemRanges[i].memory, __LINE__, MEMTRACK_INVALID_MAP, "MEM",
942611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    "%s: Flush/Invalidate offset (" PRINTF_SIZE_T_SPECIFIER ") is less than Memory Object's offset "
942711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    "(" PRINTF_SIZE_T_SPECIFIER ").",
942811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    funcName, static_cast<size_t>(pMemRanges[i].offset), static_cast<size_t>(mem_element->second.memRange.offset));
942911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
943011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if ((mem_element->second.memRange.size != VK_WHOLE_SIZE) &&
943111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                ((mem_element->second.memRange.offset + mem_element->second.memRange.size) <
943211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                 (pMemRanges[i].offset + pMemRanges[i].size))) {
943311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
943411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)pMemRanges[i].memory, __LINE__,
943511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    MEMTRACK_INVALID_MAP, "MEM", "%s: Flush/Invalidate upper-bound (" PRINTF_SIZE_T_SPECIFIER
943611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                 ") exceeds the Memory Object's upper-bound "
943711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                 "(" PRINTF_SIZE_T_SPECIFIER ").",
943811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    funcName, static_cast<size_t>(pMemRanges[i].offset + pMemRanges[i].size),
943911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                    static_cast<size_t>(mem_element->second.memRange.offset + mem_element->second.memRange.size));
944011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
944111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
944211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
944311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skipCall;
944411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
944511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
944611cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic bool validateAndCopyNoncoherentMemoryToDriver(layer_data *my_data, uint32_t memRangeCount,
944711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                     const VkMappedMemoryRange *pMemRanges) {
944811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
944911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t i = 0; i < memRangeCount; ++i) {
945011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto mem_element = my_data->memObjMap.find(pMemRanges[i].memory);
945111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (mem_element != my_data->memObjMap.end()) {
945211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (mem_element->second.pData) {
945311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                VkDeviceSize size = mem_element->second.memRange.size;
945411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                VkDeviceSize half_size = (size / 2);
945511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                char *data = static_cast<char *>(mem_element->second.pData);
945611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                for (auto j = 0; j < half_size; ++j) {
945711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    if (data[j] != NoncoherentMemoryFillValue) {
945811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
945911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)pMemRanges[i].memory, __LINE__,
946011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            MEMTRACK_INVALID_MAP, "MEM", "Memory overflow was detected on mem obj 0x%" PRIxLEAST64,
946111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            (uint64_t)pMemRanges[i].memory);
946211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    }
946311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
946411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                for (auto j = size + half_size; j < 2 * size; ++j) {
946511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    if (data[j] != NoncoherentMemoryFillValue) {
946611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
946711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)pMemRanges[i].memory, __LINE__,
946811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            MEMTRACK_INVALID_MAP, "MEM", "Memory overflow was detected on mem obj 0x%" PRIxLEAST64,
946911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                            (uint64_t)pMemRanges[i].memory);
947011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    }
947111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
947211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                memcpy(mem_element->second.pDriverData, static_cast<void *>(data + (size_t)(half_size)), (size_t)(size));
947311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
947411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
947511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
947611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return skipCall;
947711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
947811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
947911cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVkResult VKAPI_CALL
948011cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertFlushMappedMemoryRanges(VkDevice device, uint32_t memRangeCount, const VkMappedMemoryRange *pMemRanges) {
948111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
948211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
948311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
948411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
948511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
948611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= validateAndCopyNoncoherentMemoryToDriver(my_data, memRangeCount, pMemRanges);
948711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= validateMemoryIsMapped(my_data, "vkFlushMappedMemoryRanges", memRangeCount, pMemRanges);
948811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
948911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall) {
949011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        result = my_data->device_dispatch_table->FlushMappedMemoryRanges(device, memRangeCount, pMemRanges);
949111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
949211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
949311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
949411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
949511cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVkResult VKAPI_CALL
949611cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertInvalidateMappedMemoryRanges(VkDevice device, uint32_t memRangeCount, const VkMappedMemoryRange *pMemRanges) {
949711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
949811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
949911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
950011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
950111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
950211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    skipCall |= validateMemoryIsMapped(my_data, "vkInvalidateMappedMemoryRanges", memRangeCount, pMemRanges);
950311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
950411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall) {
950511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        result = my_data->device_dispatch_table->InvalidateMappedMemoryRanges(device, memRangeCount, pMemRanges);
950611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
950711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
950811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
950911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
951011cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL BindImageMemory(VkDevice device, VkImage image, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
951111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
951211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
951311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
951411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
951511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto image_node = dev_data->imageMap.find(image);
951611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (image_node != dev_data->imageMap.end()) {
951711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Track objects tied to memory
951811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        uint64_t image_handle = reinterpret_cast<uint64_t &>(image);
951911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        skipCall = set_mem_binding(dev_data, mem, image_handle, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, "vkBindImageMemory");
952011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        VkMemoryRequirements memRequirements;
952111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        lock.unlock();
952211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->GetImageMemoryRequirements(device, image, &memRequirements);
952311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        lock.lock();
952411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
952511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Track and validate bound memory range information
952611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        const auto &memEntry = dev_data->memObjMap.find(mem);
952711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (memEntry != dev_data->memObjMap.end()) {
952811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            const MEMORY_RANGE range =
952911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                insert_memory_ranges(image_handle, mem, memoryOffset, memRequirements, memEntry->second.imageRanges);
953011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall |=
953111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                validate_memory_range(dev_data, memEntry->second.bufferRanges, range, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT);
953211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
953311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
953411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        print_mem_list(dev_data);
953511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        lock.unlock();
953611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!skipCall) {
953711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            result = dev_data->device_dispatch_table->BindImageMemory(device, image, mem, memoryOffset);
953811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            lock.lock();
953911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            dev_data->memObjMap[mem].image = image;
954011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            image_node->second.mem = mem;
954111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            image_node->second.memOffset = memoryOffset;
954211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            image_node->second.memSize = memRequirements.size;
954311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            lock.unlock();
954411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
954511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } else {
954611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
954711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                reinterpret_cast<const uint64_t &>(image), __LINE__, MEMTRACK_INVALID_OBJECT, "MT",
954811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                "vkBindImageMemory: Cannot find invalid image 0x%" PRIx64 ", has it already been deleted?",
954911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                reinterpret_cast<const uint64_t &>(image));
955011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
955111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
955211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
955311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
955411cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL SetEvent(VkDevice device, VkEvent event) {
955511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
955611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
955711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
955811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
955911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto event_node = dev_data->eventMap.find(event);
956011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (event_node != dev_data->eventMap.end()) {
956111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        event_node->second.needsSignaled = false;
956211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        event_node->second.stageMask = VK_PIPELINE_STAGE_HOST_BIT;
956311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (event_node->second.write_in_use) {
956411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT,
956511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 reinterpret_cast<const uint64_t &>(event), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
956611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 "Cannot call vkSetEvent() on event 0x%" PRIxLEAST64 " that is already in use by a command buffer.",
956711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                 reinterpret_cast<const uint64_t &>(event));
956811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
956911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
957011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
957111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // Host setting event is visible to all queues immediately so update stageMask for any queue that's seen this event
957211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // TODO : For correctness this needs separate fix to verify that app doesn't make incorrect assumptions about the
957311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // ordering of this command in relation to vkCmd[Set|Reset]Events (see GH297)
957411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (auto queue_data : dev_data->queueMap) {
957511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto event_entry = queue_data.second.eventToStageMap.find(event);
957611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (event_entry != queue_data.second.eventToStageMap.end()) {
957711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            event_entry->second |= VK_PIPELINE_STAGE_HOST_BIT;
957811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
957911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
958011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skip_call)
958111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        result = dev_data->device_dispatch_table->SetEvent(device, event);
958211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
958311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
958411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
958511cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL
958611cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertQueueBindSparse(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo *pBindInfo, VkFence fence) {
958711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map);
958811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
958911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
959011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
959111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // First verify that fence is not in use
959211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (fence != VK_NULL_HANDLE) {
959311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto fence_data = dev_data->fenceMap.find(fence);
959411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if ((bindInfoCount != 0) && fence_data->second.in_use.load()) {
959511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |=
959611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
959711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        reinterpret_cast<uint64_t &>(fence), __LINE__, DRAWSTATE_INVALID_FENCE, "DS",
959811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "Fence 0x%" PRIx64 " is already in use by another submission.", reinterpret_cast<uint64_t &>(fence));
959911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
960011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!fence_data->second.needsSignaled) {
960111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skip_call |=
960211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
960311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        reinterpret_cast<uint64_t &>(fence), __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM",
960411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "Fence 0x%" PRIxLEAST64 " submitted in SIGNALED state.  Fences must be reset before being submitted",
960511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        reinterpret_cast<uint64_t &>(fence));
960611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
960711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        trackCommandBuffers(dev_data, queue, 0, nullptr, fence);
960811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
960911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (uint32_t bindIdx = 0; bindIdx < bindInfoCount; ++bindIdx) {
961011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        const VkBindSparseInfo &bindInfo = pBindInfo[bindIdx];
961111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // Track objects tied to memory
961211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t j = 0; j < bindInfo.bufferBindCount; j++) {
961311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (uint32_t k = 0; k < bindInfo.pBufferBinds[j].bindCount; k++) {
961411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (set_sparse_mem_binding(dev_data, bindInfo.pBufferBinds[j].pBinds[k].memory,
961511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                           (uint64_t)bindInfo.pBufferBinds[j].buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
961611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                           "vkQueueBindSparse"))
961711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skip_call = true;
961811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
961911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
962011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t j = 0; j < bindInfo.imageOpaqueBindCount; j++) {
962111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (uint32_t k = 0; k < bindInfo.pImageOpaqueBinds[j].bindCount; k++) {
962211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (set_sparse_mem_binding(dev_data, bindInfo.pImageOpaqueBinds[j].pBinds[k].memory,
962311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                           (uint64_t)bindInfo.pImageOpaqueBinds[j].image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
962411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                           "vkQueueBindSparse"))
962511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skip_call = true;
962611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
962711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
962811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t j = 0; j < bindInfo.imageBindCount; j++) {
962911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (uint32_t k = 0; k < bindInfo.pImageBinds[j].bindCount; k++) {
963011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (set_sparse_mem_binding(dev_data, bindInfo.pImageBinds[j].pBinds[k].memory,
963111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                           (uint64_t)bindInfo.pImageBinds[j].image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
963211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                           "vkQueueBindSparse"))
963311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skip_call = true;
963411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
963511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
963611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t i = 0; i < bindInfo.waitSemaphoreCount; ++i) {
963711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            const VkSemaphore &semaphore = bindInfo.pWaitSemaphores[i];
963811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (dev_data->semaphoreMap.find(semaphore) != dev_data->semaphoreMap.end()) {
963911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (dev_data->semaphoreMap[semaphore].signaled) {
964011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    dev_data->semaphoreMap[semaphore].signaled = false;
964111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                } else {
964211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skip_call |=
964311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
964411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                reinterpret_cast<const uint64_t &>(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
964511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                "vkQueueBindSparse: Queue 0x%" PRIx64 " is waiting on semaphore 0x%" PRIx64
964611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                " that has no way to be signaled.",
964711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                reinterpret_cast<const uint64_t &>(queue), reinterpret_cast<const uint64_t &>(semaphore));
964811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
964911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
965011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
965111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t i = 0; i < bindInfo.signalSemaphoreCount; ++i) {
965211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            const VkSemaphore &semaphore = bindInfo.pSignalSemaphores[i];
965311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (dev_data->semaphoreMap.find(semaphore) != dev_data->semaphoreMap.end()) {
965411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (dev_data->semaphoreMap[semaphore].signaled) {
965511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skip_call =
965611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
965711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                reinterpret_cast<const uint64_t &>(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
965811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                "vkQueueBindSparse: Queue 0x%" PRIx64 " is signaling semaphore 0x%" PRIx64
965911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                ", but that semaphore is already signaled.",
966011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                reinterpret_cast<const uint64_t &>(queue), reinterpret_cast<const uint64_t &>(semaphore));
966111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
966211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                dev_data->semaphoreMap[semaphore].signaled = true;
966311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
966411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
966511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
966611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    print_mem_list(dev_data);
966711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
966811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
966911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skip_call)
967011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return dev_data->device_dispatch_table->QueueBindSparse(queue, bindInfoCount, pBindInfo, fence);
967111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
967211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
967311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
967411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
967511cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL CreateSemaphore(VkDevice device, const VkSemaphoreCreateInfo *pCreateInfo,
967611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                               const VkAllocationCallbacks *pAllocator, VkSemaphore *pSemaphore) {
967711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
967811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = dev_data->device_dispatch_table->CreateSemaphore(device, pCreateInfo, pAllocator, pSemaphore);
967911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (result == VK_SUCCESS) {
968011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::lock_guard<std::mutex> lock(global_lock);
968111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        SEMAPHORE_NODE* sNode = &dev_data->semaphoreMap[*pSemaphore];
968211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        sNode->signaled = false;
968311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        sNode->queue = VK_NULL_HANDLE;
968411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        sNode->in_use.store(0);
968511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
968611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
968711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
968811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
968911cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL
969011cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCreateEvent(VkDevice device, const VkEventCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkEvent *pEvent) {
969111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
969211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = dev_data->device_dispatch_table->CreateEvent(device, pCreateInfo, pAllocator, pEvent);
969311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (result == VK_SUCCESS) {
969411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::lock_guard<std::mutex> lock(global_lock);
969511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->eventMap[*pEvent].needsSignaled = false;
969611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->eventMap[*pEvent].in_use.store(0);
969711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->eventMap[*pEvent].stageMask = VkPipelineStageFlags(0);
969811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
969911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
970011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
970111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
970211cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL CreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo,
970311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                  const VkAllocationCallbacks *pAllocator,
970411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                  VkSwapchainKHR *pSwapchain) {
970511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
970611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = dev_data->device_dispatch_table->CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain);
970711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
970811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (VK_SUCCESS == result) {
970911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        SWAPCHAIN_NODE *psc_node = new SWAPCHAIN_NODE(pCreateInfo);
971011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::lock_guard<std::mutex> lock(global_lock);
971111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_extensions.swapchainMap[*pSwapchain] = psc_node;
971211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
971311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
971411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
971511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
971611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
971711cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
971811cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks *pAllocator) {
971911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
972011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
972111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
972211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
972311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto swapchain_data = dev_data->device_extensions.swapchainMap.find(swapchain);
972411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (swapchain_data != dev_data->device_extensions.swapchainMap.end()) {
972511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (swapchain_data->second->images.size() > 0) {
972611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            for (auto swapchain_image : swapchain_data->second->images) {
972711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                auto image_sub = dev_data->imageSubresourceMap.find(swapchain_image);
972811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (image_sub != dev_data->imageSubresourceMap.end()) {
972911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    for (auto imgsubpair : image_sub->second) {
973011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        auto image_item = dev_data->imageLayoutMap.find(imgsubpair);
973111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        if (image_item != dev_data->imageLayoutMap.end()) {
973211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            dev_data->imageLayoutMap.erase(image_item);
973311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        }
973411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    }
973511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    dev_data->imageSubresourceMap.erase(image_sub);
973611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
973711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skipCall = clear_object_binding(dev_data, (uint64_t)swapchain_image,
973811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT);
973911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                dev_data->imageMap.erase(swapchain_image);
974011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
974111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
974211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        delete swapchain_data->second;
974311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_extensions.swapchainMap.erase(swapchain);
974411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
974511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
974611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall)
974711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->device_dispatch_table->DestroySwapchainKHR(device, swapchain, pAllocator);
974811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
974911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
975011cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL
975111cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pCount, VkImage *pSwapchainImages) {
975211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
975311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = dev_data->device_dispatch_table->GetSwapchainImagesKHR(device, swapchain, pCount, pSwapchainImages);
975411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
975511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (result == VK_SUCCESS && pSwapchainImages != NULL) {
975611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        // This should never happen and is checked by param checker.
975711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!pCount)
975811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return result;
975911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::lock_guard<std::mutex> lock(global_lock);
976011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        const size_t count = *pCount;
976111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        auto swapchain_node = dev_data->device_extensions.swapchainMap[swapchain];
976211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!swapchain_node->images.empty()) {
976311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            // TODO : Not sure I like the memcmp here, but it works
976411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            const bool mismatch = (swapchain_node->images.size() != count ||
976511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                   memcmp(&swapchain_node->images[0], pSwapchainImages, sizeof(swapchain_node->images[0]) * count));
976611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (mismatch) {
976711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                // TODO: Verify against Valid Usage section of extension
976811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
976911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        (uint64_t)swapchain, __LINE__, MEMTRACK_NONE, "SWAP_CHAIN",
977011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        "vkGetSwapchainInfoKHR(0x%" PRIx64
977111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        ", VK_SWAP_CHAIN_INFO_TYPE_PERSISTENT_IMAGES_KHR) returned mismatching data",
977211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        (uint64_t)(swapchain));
977311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
977411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
977511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t i = 0; i < *pCount; ++i) {
977611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            IMAGE_LAYOUT_NODE image_layout_node;
977711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            image_layout_node.layout = VK_IMAGE_LAYOUT_UNDEFINED;
977811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            image_layout_node.format = swapchain_node->createInfo.imageFormat;
977911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            auto &image_node = dev_data->imageMap[pSwapchainImages[i]];
978011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            image_node.createInfo.mipLevels = 1;
978111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            image_node.createInfo.arrayLayers = swapchain_node->createInfo.imageArrayLayers;
978211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            image_node.createInfo.usage = swapchain_node->createInfo.imageUsage;
978311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            image_node.createInfo.format = swapchain_node->createInfo.imageFormat;
978411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            image_node.createInfo.extent.width = swapchain_node->createInfo.imageExtent.width;
978511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            image_node.createInfo.extent.height = swapchain_node->createInfo.imageExtent.height;
978611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            image_node.createInfo.sharingMode = swapchain_node->createInfo.imageSharingMode;
978711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            image_node.valid = false;
978811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            image_node.mem = MEMTRACKER_SWAP_CHAIN_IMAGE_KEY;
978911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            swapchain_node->images.push_back(pSwapchainImages[i]);
979011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            ImageSubresourcePair subpair = {pSwapchainImages[i], false, VkImageSubresource()};
979111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            dev_data->imageSubresourceMap[pSwapchainImages[i]].push_back(subpair);
979211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            dev_data->imageLayoutMap[subpair] = image_layout_node;
979311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            dev_data->device_extensions.imageToSwapchainMap[pSwapchainImages[i]] = swapchain;
979411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
979511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
979611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
979711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
979811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
979911cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo) {
980011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map);
980111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
980211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skip_call = false;
980311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
980411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pPresentInfo) {
980511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::lock_guard<std::mutex> lock(global_lock);
980611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t i = 0; i < pPresentInfo->waitSemaphoreCount; ++i) {
980711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            const VkSemaphore &semaphore = pPresentInfo->pWaitSemaphores[i];
980811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (dev_data->semaphoreMap.find(semaphore) != dev_data->semaphoreMap.end()) {
980911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (dev_data->semaphoreMap[semaphore].signaled) {
981011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    dev_data->semaphoreMap[semaphore].signaled = false;
981111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                } else {
981211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    skip_call |=
981311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
981411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
981511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                "Queue 0x%" PRIx64 " is waiting on semaphore 0x%" PRIx64 " that has no way to be signaled.",
981611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                reinterpret_cast<uint64_t &>(queue), reinterpret_cast<const uint64_t &>(semaphore));
981711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
981811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
981911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
982011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        VkDeviceMemory mem;
982111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        for (uint32_t i = 0; i < pPresentInfo->swapchainCount; ++i) {
982211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            auto swapchain_data = dev_data->device_extensions.swapchainMap.find(pPresentInfo->pSwapchains[i]);
982311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            if (swapchain_data != dev_data->device_extensions.swapchainMap.end() &&
982411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                pPresentInfo->pImageIndices[i] < swapchain_data->second->images.size()) {
982511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                VkImage image = swapchain_data->second->images[pPresentInfo->pImageIndices[i]];
982611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#if MTMERGESOURCE
982711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skip_call |=
982811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    get_mem_binding_from_object(dev_data, (uint64_t)(image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
982911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                skip_call |= validate_memory_is_valid(dev_data, mem, "vkQueuePresentKHR()", image);
983011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#endif
983111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                vector<VkImageLayout> layouts;
983211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                if (FindLayouts(dev_data, image, layouts)) {
983311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    for (auto layout : layouts) {
983411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        if (layout != VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) {
983511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                            skip_call |=
983611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT,
983711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        reinterpret_cast<uint64_t &>(queue), __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
983811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        "Images passed to present must be in layout "
983911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        "PRESENT_SOURCE_KHR but is in %s",
984011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                        string_VkImageLayout(layout));
984111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        }
984211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                    }
984311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                }
984411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            }
984511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
984611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
984711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
984811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skip_call)
984911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        result = dev_data->device_dispatch_table->QueuePresentKHR(queue, pPresentInfo);
985011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
985111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
985211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
985311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
985411cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL AcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout,
985511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                   VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex) {
985611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
985711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
985811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    bool skipCall = false;
985911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
986011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::unique_lock<std::mutex> lock(global_lock);
986111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (semaphore != VK_NULL_HANDLE &&
986211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->semaphoreMap.find(semaphore) != dev_data->semaphoreMap.end()) {
986311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (dev_data->semaphoreMap[semaphore].signaled) {
986411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            skipCall = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
986511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                               reinterpret_cast<const uint64_t &>(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
986611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                               "vkAcquireNextImageKHR: Semaphore must not be currently signaled or in a wait state");
986711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        }
986811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        dev_data->semaphoreMap[semaphore].signaled = true;
986911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
987011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    auto fence_data = dev_data->fenceMap.find(fence);
987111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (fence_data != dev_data->fenceMap.end()) {
987211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        fence_data->second.swapchain = swapchain;
987311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
987411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    lock.unlock();
987511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
987611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!skipCall) {
987711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        result =
987811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            dev_data->device_dispatch_table->AcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, pImageIndex);
987911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
988011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
988111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return result;
988211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
988311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
988411cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL
988511cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertCreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
988611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                             const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT *pMsgCallback) {
988711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
988811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table;
988911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkResult res = pTable->CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
989011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (VK_SUCCESS == res) {
989111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        std::lock_guard<std::mutex> lock(global_lock);
989211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        res = layer_create_msg_callback(my_data->report_data, pCreateInfo, pAllocator, pMsgCallback);
989311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
989411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return res;
989511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
989611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
989711cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL DestroyDebugReportCallbackEXT(VkInstance instance,
989811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                         VkDebugReportCallbackEXT msgCallback,
989911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                         const VkAllocationCallbacks *pAllocator) {
990011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
990111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table;
990211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    pTable->DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);
990311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    std::lock_guard<std::mutex> lock(global_lock);
990411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_destroy_msg_callback(my_data->report_data, msgCallback, pAllocator);
990511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
990611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
990711cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
990811cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertDebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t object,
990911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                      size_t location, int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
991011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
991111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    my_data->instance_dispatch_table->DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix,
991211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                            pMsg);
991311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
991411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
991511cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
991611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                  const char *pLayerName, uint32_t *pCount,
991711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                  VkExtensionProperties *pProperties) {
991811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pLayerName && !strcmp(pLayerName, global_layer.layerName))
991911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return util_GetExtensionProperties(0, NULL, pCount, pProperties);
992011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
992111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    assert(physicalDevice);
992211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
992311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    dispatch_key key = get_dispatch_key(physicalDevice);
992411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *my_data = get_my_data_ptr(key, layer_data_map);
992511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return my_data->instance_dispatch_table->EnumerateDeviceExtensionProperties(physicalDevice, NULL, pCount, pProperties);
992611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
992711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
992811cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic PFN_vkVoidFunction
992911cd02dfb91661c65134cac258cf5924270e9d2Dan Albertintercept_core_instance_command(const char *name);
993011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
993111cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic PFN_vkVoidFunction
993211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertintercept_core_device_command(const char *name);
993311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
993411cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic PFN_vkVoidFunction
993511cd02dfb91661c65134cac258cf5924270e9d2Dan Albertintercept_khr_swapchain_command(const char *name, VkDevice dev);
993611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
993711cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice dev, const char *funcName) {
993811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    PFN_vkVoidFunction proc = intercept_core_device_command(funcName);
993911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (proc)
994011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return proc;
994111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
994211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    assert(dev);
994311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
994411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    proc = intercept_khr_swapchain_command(funcName, dev);
994511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (proc)
994611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return proc;
994711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
994811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *dev_data;
994911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    dev_data = get_my_data_ptr(get_dispatch_key(dev), layer_data_map);
995011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
995111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkLayerDispatchTable *pTable = dev_data->device_dispatch_table;
995211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    {
995311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (pTable->GetDeviceProcAddr == NULL)
995411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return NULL;
995511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return pTable->GetDeviceProcAddr(dev, funcName);
995611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
995711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
995811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
995911cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetInstanceProcAddr(VkInstance instance, const char *funcName) {
996011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    PFN_vkVoidFunction proc = intercept_core_instance_command(funcName);
996111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!proc)
996211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        proc = intercept_core_device_command(funcName);
996311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!proc)
996411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        proc = intercept_khr_swapchain_command(funcName, VK_NULL_HANDLE);
996511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (proc)
996611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return proc;
996711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
996811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    assert(instance);
996911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
997011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    layer_data *my_data;
997111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
997211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    proc = debug_report_get_instance_proc_addr(my_data->report_data, funcName);
997311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (proc)
997411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return proc;
997511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
997611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table;
997711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (pTable->GetInstanceProcAddr == NULL)
997811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return NULL;
997911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return pTable->GetInstanceProcAddr(instance, funcName);
998011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
998111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
998211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic PFN_vkVoidFunction
998311cd02dfb91661c65134cac258cf5924270e9d2Dan Albertintercept_core_instance_command(const char *name) {
998411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    static const struct {
998511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        const char *name;
998611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        PFN_vkVoidFunction proc;
998711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } core_instance_commands[] = {
998811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        { "vkGetInstanceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetInstanceProcAddr) },
998911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        { "vkGetDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceProcAddr) },
999011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        { "vkCreateInstance", reinterpret_cast<PFN_vkVoidFunction>(CreateInstance) },
999111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        { "vkCreateDevice", reinterpret_cast<PFN_vkVoidFunction>(CreateDevice) },
999211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        { "vkDestroyInstance", reinterpret_cast<PFN_vkVoidFunction>(DestroyInstance) },
999311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        { "vkEnumerateDeviceExtensionProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateDeviceExtensionProperties) },
999411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    };
999511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
999611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // we should never be queried for these commands
999711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    assert(strcmp(name, "vkEnumerateInstanceLayerProperties") &&
999811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert           strcmp(name, "vkEnumerateInstanceExtensionProperties") &&
999911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert           strcmp(name, "vkEnumerateDeviceLayerProperties"));
1000011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
1000111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (size_t i = 0; i < ARRAY_SIZE(core_instance_commands); i++) {
1000211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!strcmp(core_instance_commands[i].name, name))
1000311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return core_instance_commands[i].proc;
1000411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
1000511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
1000611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return nullptr;
1000711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
1000811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
1000911cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic PFN_vkVoidFunction
1001011cd02dfb91661c65134cac258cf5924270e9d2Dan Albertintercept_core_device_command(const char *name) {
1001111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    static const struct {
1001211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        const char *name;
1001311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        PFN_vkVoidFunction proc;
1001411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } core_device_commands[] = {
1001511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkGetDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceProcAddr)},
1001611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkQueueSubmit", reinterpret_cast<PFN_vkVoidFunction>(QueueSubmit)},
1001711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkWaitForFences", reinterpret_cast<PFN_vkVoidFunction>(WaitForFences)},
1001811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkGetFenceStatus", reinterpret_cast<PFN_vkVoidFunction>(GetFenceStatus)},
1001911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkQueueWaitIdle", reinterpret_cast<PFN_vkVoidFunction>(QueueWaitIdle)},
1002011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkDeviceWaitIdle", reinterpret_cast<PFN_vkVoidFunction>(DeviceWaitIdle)},
1002111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkGetDeviceQueue", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceQueue)},
1002211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkDestroyInstance", reinterpret_cast<PFN_vkVoidFunction>(DestroyInstance)},
1002311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkDestroyDevice", reinterpret_cast<PFN_vkVoidFunction>(DestroyDevice)},
1002411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkDestroyFence", reinterpret_cast<PFN_vkVoidFunction>(DestroyFence)},
1002511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkResetFences", reinterpret_cast<PFN_vkVoidFunction>(ResetFences)},
1002611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkDestroySemaphore", reinterpret_cast<PFN_vkVoidFunction>(DestroySemaphore)},
1002711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkDestroyEvent", reinterpret_cast<PFN_vkVoidFunction>(DestroyEvent)},
1002811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkDestroyQueryPool", reinterpret_cast<PFN_vkVoidFunction>(DestroyQueryPool)},
1002911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkDestroyBuffer", reinterpret_cast<PFN_vkVoidFunction>(DestroyBuffer)},
1003011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkDestroyBufferView", reinterpret_cast<PFN_vkVoidFunction>(DestroyBufferView)},
1003111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkDestroyImage", reinterpret_cast<PFN_vkVoidFunction>(DestroyImage)},
1003211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkDestroyImageView", reinterpret_cast<PFN_vkVoidFunction>(DestroyImageView)},
1003311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkDestroyShaderModule", reinterpret_cast<PFN_vkVoidFunction>(DestroyShaderModule)},
1003411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkDestroyPipeline", reinterpret_cast<PFN_vkVoidFunction>(DestroyPipeline)},
1003511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkDestroyPipelineLayout", reinterpret_cast<PFN_vkVoidFunction>(DestroyPipelineLayout)},
1003611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkDestroySampler", reinterpret_cast<PFN_vkVoidFunction>(DestroySampler)},
1003711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkDestroyDescriptorSetLayout", reinterpret_cast<PFN_vkVoidFunction>(DestroyDescriptorSetLayout)},
1003811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkDestroyDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(DestroyDescriptorPool)},
1003911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkDestroyFramebuffer", reinterpret_cast<PFN_vkVoidFunction>(DestroyFramebuffer)},
1004011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkDestroyRenderPass", reinterpret_cast<PFN_vkVoidFunction>(DestroyRenderPass)},
1004111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCreateBuffer", reinterpret_cast<PFN_vkVoidFunction>(CreateBuffer)},
1004211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCreateBufferView", reinterpret_cast<PFN_vkVoidFunction>(CreateBufferView)},
1004311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCreateImage", reinterpret_cast<PFN_vkVoidFunction>(CreateImage)},
1004411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCreateImageView", reinterpret_cast<PFN_vkVoidFunction>(CreateImageView)},
1004511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCreateFence", reinterpret_cast<PFN_vkVoidFunction>(CreateFence)},
1004611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCreatePipelineCache", reinterpret_cast<PFN_vkVoidFunction>(CreatePipelineCache)},
1004711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkDestroyPipelineCache", reinterpret_cast<PFN_vkVoidFunction>(DestroyPipelineCache)},
1004811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkGetPipelineCacheData", reinterpret_cast<PFN_vkVoidFunction>(GetPipelineCacheData)},
1004911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkMergePipelineCaches", reinterpret_cast<PFN_vkVoidFunction>(MergePipelineCaches)},
1005011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCreateGraphicsPipelines", reinterpret_cast<PFN_vkVoidFunction>(CreateGraphicsPipelines)},
1005111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCreateComputePipelines", reinterpret_cast<PFN_vkVoidFunction>(CreateComputePipelines)},
1005211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCreateSampler", reinterpret_cast<PFN_vkVoidFunction>(CreateSampler)},
1005311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCreateDescriptorSetLayout", reinterpret_cast<PFN_vkVoidFunction>(CreateDescriptorSetLayout)},
1005411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCreatePipelineLayout", reinterpret_cast<PFN_vkVoidFunction>(CreatePipelineLayout)},
1005511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCreateDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(CreateDescriptorPool)},
1005611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkResetDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(ResetDescriptorPool)},
1005711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkAllocateDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(AllocateDescriptorSets)},
1005811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkFreeDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(FreeDescriptorSets)},
1005911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkUpdateDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(UpdateDescriptorSets)},
1006011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCreateCommandPool", reinterpret_cast<PFN_vkVoidFunction>(CreateCommandPool)},
1006111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkDestroyCommandPool", reinterpret_cast<PFN_vkVoidFunction>(DestroyCommandPool)},
1006211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkResetCommandPool", reinterpret_cast<PFN_vkVoidFunction>(ResetCommandPool)},
1006311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCreateQueryPool", reinterpret_cast<PFN_vkVoidFunction>(CreateQueryPool)},
1006411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkAllocateCommandBuffers", reinterpret_cast<PFN_vkVoidFunction>(AllocateCommandBuffers)},
1006511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkFreeCommandBuffers", reinterpret_cast<PFN_vkVoidFunction>(FreeCommandBuffers)},
1006611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkBeginCommandBuffer", reinterpret_cast<PFN_vkVoidFunction>(BeginCommandBuffer)},
1006711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkEndCommandBuffer", reinterpret_cast<PFN_vkVoidFunction>(EndCommandBuffer)},
1006811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkResetCommandBuffer", reinterpret_cast<PFN_vkVoidFunction>(ResetCommandBuffer)},
1006911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdBindPipeline", reinterpret_cast<PFN_vkVoidFunction>(CmdBindPipeline)},
1007011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdSetViewport", reinterpret_cast<PFN_vkVoidFunction>(CmdSetViewport)},
1007111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdSetScissor", reinterpret_cast<PFN_vkVoidFunction>(CmdSetScissor)},
1007211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdSetLineWidth", reinterpret_cast<PFN_vkVoidFunction>(CmdSetLineWidth)},
1007311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdSetDepthBias", reinterpret_cast<PFN_vkVoidFunction>(CmdSetDepthBias)},
1007411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdSetBlendConstants", reinterpret_cast<PFN_vkVoidFunction>(CmdSetBlendConstants)},
1007511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdSetDepthBounds", reinterpret_cast<PFN_vkVoidFunction>(CmdSetDepthBounds)},
1007611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdSetStencilCompareMask", reinterpret_cast<PFN_vkVoidFunction>(CmdSetStencilCompareMask)},
1007711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdSetStencilWriteMask", reinterpret_cast<PFN_vkVoidFunction>(CmdSetStencilWriteMask)},
1007811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdSetStencilReference", reinterpret_cast<PFN_vkVoidFunction>(CmdSetStencilReference)},
1007911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdBindDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(CmdBindDescriptorSets)},
1008011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdBindVertexBuffers", reinterpret_cast<PFN_vkVoidFunction>(CmdBindVertexBuffers)},
1008111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdBindIndexBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdBindIndexBuffer)},
1008211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdDraw", reinterpret_cast<PFN_vkVoidFunction>(CmdDraw)},
1008311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdDrawIndexed", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndexed)},
1008411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdDrawIndirect", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndirect)},
1008511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdDrawIndexedIndirect", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndexedIndirect)},
1008611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdDispatch", reinterpret_cast<PFN_vkVoidFunction>(CmdDispatch)},
1008711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdDispatchIndirect", reinterpret_cast<PFN_vkVoidFunction>(CmdDispatchIndirect)},
1008811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdCopyBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyBuffer)},
1008911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdCopyImage", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyImage)},
1009011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdBlitImage", reinterpret_cast<PFN_vkVoidFunction>(CmdBlitImage)},
1009111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdCopyBufferToImage", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyBufferToImage)},
1009211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdCopyImageToBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyImageToBuffer)},
1009311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdUpdateBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdUpdateBuffer)},
1009411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdFillBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdFillBuffer)},
1009511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdClearColorImage", reinterpret_cast<PFN_vkVoidFunction>(CmdClearColorImage)},
1009611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdClearDepthStencilImage", reinterpret_cast<PFN_vkVoidFunction>(CmdClearDepthStencilImage)},
1009711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdClearAttachments", reinterpret_cast<PFN_vkVoidFunction>(CmdClearAttachments)},
1009811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdResolveImage", reinterpret_cast<PFN_vkVoidFunction>(CmdResolveImage)},
1009911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdSetEvent", reinterpret_cast<PFN_vkVoidFunction>(CmdSetEvent)},
1010011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdResetEvent", reinterpret_cast<PFN_vkVoidFunction>(CmdResetEvent)},
1010111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdWaitEvents", reinterpret_cast<PFN_vkVoidFunction>(CmdWaitEvents)},
1010211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdPipelineBarrier", reinterpret_cast<PFN_vkVoidFunction>(CmdPipelineBarrier)},
1010311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdBeginQuery", reinterpret_cast<PFN_vkVoidFunction>(CmdBeginQuery)},
1010411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdEndQuery", reinterpret_cast<PFN_vkVoidFunction>(CmdEndQuery)},
1010511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdResetQueryPool", reinterpret_cast<PFN_vkVoidFunction>(CmdResetQueryPool)},
1010611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdCopyQueryPoolResults", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyQueryPoolResults)},
1010711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdPushConstants", reinterpret_cast<PFN_vkVoidFunction>(CmdPushConstants)},
1010811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdWriteTimestamp", reinterpret_cast<PFN_vkVoidFunction>(CmdWriteTimestamp)},
1010911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCreateFramebuffer", reinterpret_cast<PFN_vkVoidFunction>(CreateFramebuffer)},
1011011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCreateShaderModule", reinterpret_cast<PFN_vkVoidFunction>(CreateShaderModule)},
1011111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCreateRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CreateRenderPass)},
1011211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdBeginRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CmdBeginRenderPass)},
1011311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdNextSubpass", reinterpret_cast<PFN_vkVoidFunction>(CmdNextSubpass)},
1011411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdEndRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CmdEndRenderPass)},
1011511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCmdExecuteCommands", reinterpret_cast<PFN_vkVoidFunction>(CmdExecuteCommands)},
1011611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkSetEvent", reinterpret_cast<PFN_vkVoidFunction>(SetEvent)},
1011711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkMapMemory", reinterpret_cast<PFN_vkVoidFunction>(MapMemory)},
1011811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkUnmapMemory", reinterpret_cast<PFN_vkVoidFunction>(UnmapMemory)},
1011911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkFlushMappedMemoryRanges", reinterpret_cast<PFN_vkVoidFunction>(FlushMappedMemoryRanges)},
1012011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkInvalidateMappedMemoryRanges", reinterpret_cast<PFN_vkVoidFunction>(InvalidateMappedMemoryRanges)},
1012111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkAllocateMemory", reinterpret_cast<PFN_vkVoidFunction>(AllocateMemory)},
1012211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkFreeMemory", reinterpret_cast<PFN_vkVoidFunction>(FreeMemory)},
1012311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkBindBufferMemory", reinterpret_cast<PFN_vkVoidFunction>(BindBufferMemory)},
1012411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkGetBufferMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(GetBufferMemoryRequirements)},
1012511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkGetImageMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(GetImageMemoryRequirements)},
1012611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkGetQueryPoolResults", reinterpret_cast<PFN_vkVoidFunction>(GetQueryPoolResults)},
1012711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkBindImageMemory", reinterpret_cast<PFN_vkVoidFunction>(BindImageMemory)},
1012811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkQueueBindSparse", reinterpret_cast<PFN_vkVoidFunction>(QueueBindSparse)},
1012911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCreateSemaphore", reinterpret_cast<PFN_vkVoidFunction>(CreateSemaphore)},
1013011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        {"vkCreateEvent", reinterpret_cast<PFN_vkVoidFunction>(CreateEvent)},
1013111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    };
1013211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
1013311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (size_t i = 0; i < ARRAY_SIZE(core_device_commands); i++) {
1013411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!strcmp(core_device_commands[i].name, name))
1013511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return core_device_commands[i].proc;
1013611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
1013711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
1013811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return nullptr;
1013911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
1014011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
1014111cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic PFN_vkVoidFunction
1014211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertintercept_khr_swapchain_command(const char *name, VkDevice dev) {
1014311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    static const struct {
1014411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        const char *name;
1014511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        PFN_vkVoidFunction proc;
1014611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    } khr_swapchain_commands[] = {
1014711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        { "vkCreateSwapchainKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateSwapchainKHR) },
1014811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        { "vkDestroySwapchainKHR", reinterpret_cast<PFN_vkVoidFunction>(DestroySwapchainKHR) },
1014911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        { "vkGetSwapchainImagesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetSwapchainImagesKHR) },
1015011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        { "vkAcquireNextImageKHR", reinterpret_cast<PFN_vkVoidFunction>(AcquireNextImageKHR) },
1015111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        { "vkQueuePresentKHR", reinterpret_cast<PFN_vkVoidFunction>(QueuePresentKHR) },
1015211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    };
1015311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
1015411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (dev) {
1015511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        layer_data *dev_data = get_my_data_ptr(get_dispatch_key(dev), layer_data_map);
1015611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!dev_data->device_extensions.wsi_enabled)
1015711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return nullptr;
1015811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
1015911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
1016011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    for (size_t i = 0; i < ARRAY_SIZE(khr_swapchain_commands); i++) {
1016111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        if (!strcmp(khr_swapchain_commands[i].name, name))
1016211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert            return khr_swapchain_commands[i].proc;
1016311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    }
1016411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
1016511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return nullptr;
1016611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
1016711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
1016811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} // namespace core_validation
1016911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
1017011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// vk_layer_logging.h expects these to be defined
1017111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
1017211cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR VkResult VKAPI_CALL
1017311cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertvkCreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
1017411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                               const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT *pMsgCallback) {
1017511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return core_validation::CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
1017611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
1017711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
1017811cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
1017911cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertvkDestroyDebugReportCallbackEXT(VkInstance instance,
1018011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                VkDebugReportCallbackEXT msgCallback,
1018111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                const VkAllocationCallbacks *pAllocator) {
1018211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    core_validation::DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);
1018311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
1018411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
1018511cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVKAPI_ATTR void VKAPI_CALL
1018611cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertvkDebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t object,
1018711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                        size_t location, int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
1018811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    core_validation::DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, pMsg);
1018911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
1019011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
1019111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// loader-layer interface v0
1019211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
1019311cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
1019411cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertvkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount, VkExtensionProperties *pProperties) {
1019511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return util_GetExtensionProperties(1, core_validation::instance_extensions, pCount, pProperties);
1019611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
1019711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
1019811cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
1019911cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertvkEnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties) {
1020011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return util_GetLayerProperties(1, &core_validation::global_layer, pCount, pProperties);
1020111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
1020211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
1020311cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
1020411cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertvkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount, VkLayerProperties *pProperties) {
1020511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return util_GetLayerProperties(1, &core_validation::global_layer, pCount, pProperties);
1020611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
1020711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
1020811cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
1020911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                                    const char *pLayerName, uint32_t *pCount,
1021011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert                                                                                    VkExtensionProperties *pProperties) {
1021111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    // the layer command handles VK_NULL_HANDLE just fine
1021211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return core_validation::EnumerateDeviceExtensionProperties(VK_NULL_HANDLE, pLayerName, pCount, pProperties);
1021311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
1021411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
1021511cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev, const char *funcName) {
1021611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return core_validation::GetDeviceProcAddr(dev, funcName);
1021711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
1021811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
1021911cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertVK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) {
1022011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!strcmp(funcName, "vkEnumerateInstanceLayerProperties"))
1022111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return reinterpret_cast<PFN_vkVoidFunction>(vkEnumerateInstanceLayerProperties);
1022211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!strcmp(funcName, "vkEnumerateDeviceLayerProperties"))
1022311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return reinterpret_cast<PFN_vkVoidFunction>(vkEnumerateDeviceLayerProperties);
1022411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!strcmp(funcName, "vkEnumerateInstanceExtensionProperties"))
1022511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return reinterpret_cast<PFN_vkVoidFunction>(vkEnumerateInstanceExtensionProperties);
1022611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    if (!strcmp(funcName, "vkGetInstanceProcAddr"))
1022711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert        return reinterpret_cast<PFN_vkVoidFunction>(vkGetInstanceProcAddr);
1022811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert
1022911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert    return core_validation::GetInstanceProcAddr(instance, funcName);
1023011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert}
10231