core_validation.cpp revision 9784e78683f658f304062235ceb2dd2c2652c357
14f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes/* Copyright (c) 2015-2017 The Khronos Group Inc.
24f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes * Copyright (c) 2015-2017 Valve Corporation
34f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes * Copyright (c) 2015-2017 LunarG, Inc.
44f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes * Copyright (C) 2015-2017 Google Inc.
55b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis *
643b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * Licensed under the Apache License, Version 2.0 (the "License");
743b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * you may not use this file except in compliance with the License.
843b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * You may obtain a copy of the License at
95b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis *
1043b53e83705f02245da6ae61e31273866a35b833Jon Ashburn *     http://www.apache.org/licenses/LICENSE-2.0
115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis *
1243b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * Unless required by applicable law or agreed to in writing, software
1343b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * distributed under the License is distributed on an "AS IS" BASIS,
1443b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1543b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * See the License for the specific language governing permissions and
1643b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * limitations under the License.
175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis *
185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis * Author: Cody Northrop <cnorthrop@google.com>
195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis * Author: Michael Lentine <mlentine@google.com>
205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis * Author: Tobin Ehlis <tobine@google.com>
215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis * Author: Chia-I Wu <olv@google.com>
225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis * Author: Chris Forbes <chrisf@ijw.co.nz>
235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis * Author: Mark Lobodzinski <mark@lunarg.com>
245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis * Author: Ian Elliott <ianelliott@google.com>
2560cbbd8f316f5dfc7997bb66833a2e624f832e37Mark Lobodzinski * Author: Dave Houlton <daveh@lunarg.com>
2660cbbd8f316f5dfc7997bb66833a2e624f832e37Mark Lobodzinski * Author: Dustin Graves <dustin@lunarg.com>
2760cbbd8f316f5dfc7997bb66833a2e624f832e37Mark Lobodzinski * Author: Jeremy Hayes <jeremy@lunarg.com>
2860cbbd8f316f5dfc7997bb66833a2e624f832e37Mark Lobodzinski * Author: Jon Ashburn <jon@lunarg.com>
2960cbbd8f316f5dfc7997bb66833a2e624f832e37Mark Lobodzinski * Author: Karl Schultz <karl@lunarg.com>
3060cbbd8f316f5dfc7997bb66833a2e624f832e37Mark Lobodzinski * Author: Mark Young <marky@lunarg.com>
3160cbbd8f316f5dfc7997bb66833a2e624f832e37Mark Lobodzinski * Author: Mike Schuchardt <mikes@lunarg.com>
3260cbbd8f316f5dfc7997bb66833a2e624f832e37Mark Lobodzinski * Author: Mike Weiblen <mikew@lunarg.com>
3360cbbd8f316f5dfc7997bb66833a2e624f832e37Mark Lobodzinski * Author: Tony Barbour <tony@LunarG.com>
345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis */
355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Allow use of STL min and max functions in Windows
375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#define NOMINMAX
385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3994c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis#include <SPIRV/spirv.hpp>
4094c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis#include <algorithm>
4194c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis#include <assert.h>
4294c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis#include <iostream>
4394c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis#include <list>
4494c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis#include <map>
45b9e992386a44404152747d66817a733aa127e281Jeremy Hayes#include <mutex>
4694c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis#include <set>
4768d157d34807071526e5d78b3b3b68c5a4c6185fMark Lobodzinski#include <sstream>
485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include <stdio.h>
495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include <stdlib.h>
505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include <string.h>
5194c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis#include <string>
52dd725b03ae4d1296a722d0ec5c9fe63941cabe4bChris Forbes#include <tuple>
535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include "vk_loader_platform.h"
555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include "vk_dispatch_table_helper.h"
5668d157d34807071526e5d78b3b3b68c5a4c6185fMark Lobodzinski#include "vk_enum_string_helper.h"
575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#if defined(__GNUC__)
585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#pragma GCC diagnostic ignored "-Wwrite-strings"
595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#endif
605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#if defined(__GNUC__)
615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#pragma GCC diagnostic warning "-Wwrite-strings"
625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#endif
635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include "core_validation.h"
64c06c9b88f5f5bcc7033ba41d5547b048fa6015a4Mark Lobodzinski#include "buffer_validation.h"
655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include "vk_layer_table.h"
665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include "vk_layer_data.h"
675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include "vk_layer_extension_utils.h"
685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include "vk_layer_utils.h"
69b1f65702539fd041337fccd493dc6d38dd2a603eChris Forbes#include "spirv-tools/libspirv.h"
705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#if defined __ANDROID__
725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include <android/log.h>
735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#define LOGCONSOLE(...) ((void)__android_log_print(ANDROID_LOG_INFO, "DS", __VA_ARGS__))
745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#else
75cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#define LOGCONSOLE(...)      \
76cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    {                        \
77cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        printf(__VA_ARGS__); \
78cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        printf("\n");        \
79c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    }
805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#endif
815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
82d147a5463f8581604ca542aa1a44a27e512e0f60Mike Stroyan// This intentionally includes a cpp file
83d147a5463f8581604ca542aa1a44a27e512e0f60Mike Stroyan#include "vk_safe_struct.cpp"
84d147a5463f8581604ca542aa1a44a27e512e0f60Mike Stroyan
85414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Muellerusing namespace std;
86414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller
87d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wunamespace core_validation {
88d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisusing std::unordered_map;
905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisusing std::unordered_set;
915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// WSI Image Objects bypass usual Image Object creation methods.  A special Memory
935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Object value will be used to identify them internally.
945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic const VkDeviceMemory MEMTRACKER_SWAP_CHAIN_IMAGE_KEY = (VkDeviceMemory)(-1);
95888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis// 2nd special memory handle used to flag object as unbound from memory
96888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlisstatic const VkDeviceMemory MEMORY_UNBOUND = VkDeviceMemory(~((uint64_t)(0)) - 1);
97b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis
982e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill// A special value of (0xFFFFFFFF, 0xFFFFFFFF) indicates that the surface size will be determined
992e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill// by the extent of a swapchain targeting the surface.
1002e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madillstatic const uint32_t kSurfaceSizeFromSwapchain = 0xFFFFFFFFu;
1012e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill
1025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstruct devExts {
103e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool wsi_enabled;
104c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young    bool wsi_display_swapchain_enabled;
1053f687bf405355f3eec6bd1bc0e8d04daba37a0f9Tobin Ehlis    unordered_map<VkSwapchainKHR, unique_ptr<SWAPCHAIN_NODE>> swapchainMap;
1065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkImage, VkSwapchainKHR> imageToSwapchainMap;
1075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis};
1085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// fwd decls
1105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstruct shader_module;
1115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
112f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbesstruct instance_layer_data {
113d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    VkInstance instance = VK_NULL_HANDLE;
114d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    debug_report_data *report_data = nullptr;
1155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<VkDebugReportCallbackEXT> logging_callback;
1169172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    VkLayerInstanceDispatchTable dispatch_table;
1179172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes
118219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes    CALL_STATE vkEnumeratePhysicalDevicesState = UNCALLED;
119219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes    uint32_t physical_devices_count = 0;
120b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    CALL_STATE vkEnumeratePhysicalDeviceGroupsState = UNCALLED;
121b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    uint32_t physical_device_groups_count = 0;
122219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes    CHECK_DISABLED disabled = {};
123219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes
124f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes    unordered_map<VkPhysicalDevice, PHYSICAL_DEVICE_STATE> physical_device_map;
125747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    unordered_map<VkSurfaceKHR, SURFACE_STATE> surface_map;
126747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
127747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool surfaceExtensionEnabled = false;
128747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool displayExtensionEnabled = false;
129747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool androidSurfaceExtensionEnabled = false;
130747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool mirSurfaceExtensionEnabled = false;
131747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool waylandSurfaceExtensionEnabled = false;
132747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool win32SurfaceExtensionEnabled = false;
133747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool xcbSurfaceExtensionEnabled = false;
134747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool xlibSurfaceExtensionEnabled = false;
135f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes};
136f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes
137f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbesstruct layer_data {
138f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes    debug_report_data *report_data = nullptr;
1394a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkLayerDispatchTable dispatch_table;
14094c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis
141d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    devExts device_extensions = {};
142cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    unordered_set<VkQueue> queues;  // All queues under given device
1435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Global set of all cmdBuffers that are inFlight on this device
1445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_set<VkCommandBuffer> globalInFlightCmdBuffers;
1455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Layer specific data
146d31a44af6da568692a73201825459689c9431867Tobin Ehlis    unordered_map<VkSampler, unique_ptr<SAMPLER_STATE>> samplerMap;
14779fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis    unordered_map<VkImageView, unique_ptr<IMAGE_VIEW_STATE>> imageViewMap;
1481facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    unordered_map<VkImage, unique_ptr<IMAGE_STATE>> imageMap;
14939267c0c27b8f032f05a6747eb02d4508247fdc1Tobin Ehlis    unordered_map<VkBufferView, unique_ptr<BUFFER_VIEW_STATE>> bufferViewMap;
1505cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    unordered_map<VkBuffer, unique_ptr<BUFFER_STATE>> bufferMap;
1514c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    unordered_map<VkPipeline, PIPELINE_STATE *> pipelineMap;
1528d6a38de0389036581ada119e548180c614fe0efChris Forbes    unordered_map<VkCommandPool, COMMAND_POOL_NODE> commandPoolMap;
153a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis    unordered_map<VkDescriptorPool, DESCRIPTOR_POOL_STATE *> descriptorPoolMap;
154397d27da37095073c8b86f9ff5289d0a39ce486eTobin Ehlis    unordered_map<VkDescriptorSet, cvdescriptorset::DescriptorSet *> setMap;
155cb9ce9e05b8e939d3da35c64997c70049877f4feTobin Ehlis    unordered_map<VkDescriptorSetLayout, cvdescriptorset::DescriptorSetLayout *> descriptorSetLayoutMap;
1565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkPipelineLayout, PIPELINE_LAYOUT_NODE> pipelineLayoutMap;
15757fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    unordered_map<VkDeviceMemory, unique_ptr<DEVICE_MEM_INFO>> memObjMap;
1585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkFence, FENCE_NODE> fenceMap;
15936c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlis    unordered_map<VkQueue, QUEUE_STATE> queueMap;
1604710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis    unordered_map<VkEvent, EVENT_STATE> eventMap;
1615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<QueryObject, bool> queryToStateMap;
1625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkQueryPool, QUERY_POOL_NODE> queryPoolMap;
1635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkSemaphore, SEMAPHORE_NODE> semaphoreMap;
16472d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis    unordered_map<VkCommandBuffer, GLOBAL_CB_NODE *> commandBufferMap;
165c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    unordered_map<VkFramebuffer, unique_ptr<FRAMEBUFFER_STATE>> frameBufferMap;
1665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkImage, vector<ImageSubresourcePair>> imageSubresourceMap;
1675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> imageLayoutMap;
168127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis    unordered_map<VkRenderPass, unique_ptr<RENDER_PASS_STATE>> renderPassMap;
169918c283ac4f8c604b79abd0c8b5706d2a7352a34Chris Forbes    unordered_map<VkShaderModule, unique_ptr<shader_module>> shaderModuleMap;
17007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
171d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    VkDevice device = VK_NULL_HANDLE;
172ec85232c4d8d9ddf7d2ae57cb8203c5ab52c1106Mark Lobodzinski    VkPhysicalDevice physical_device = VK_NULL_HANDLE;
1735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
174cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    instance_layer_data *instance_data = nullptr;  // from device to enclosing instance
17507a464bd7fec9583f346b8c4b8d43c88d2e9ffa4Chris Forbes
176f71dd305f197826a61f398bff725267a20ea1d90Chris Forbes    VkPhysicalDeviceFeatures enabled_features = {};
1775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Device specific data
178d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    PHYS_DEV_PROPERTIES_NODE phys_dev_properties = {};
179d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    VkPhysicalDeviceMemoryProperties phys_dev_mem_props = {};
180e47dbc3f3340fa177d877a67b2adb76a570027e5Mark Lobodzinski    VkPhysicalDeviceProperties phys_dev_props = {};
1815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis};
1825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
183b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis// TODO : Do we need to guard access to layer_data_map w/ lock?
184b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlisstatic unordered_map<void *, layer_data *> layer_data_map;
185f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbesstatic unordered_map<void *, instance_layer_data *> instance_layer_data_map;
186b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis
187b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Youngstatic uint32_t loader_layer_if_version = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
188b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
189e11120777bcd1543455d1de54b89292879bcd2bbChia-I Wustatic const VkLayerProperties global_layer = {
190f1ea418f193d10a8455cdf47e0eeeeb1f4d8b5bfJon Ashburn    "VK_LAYER_LUNARG_core_validation", VK_LAYER_API_VERSION, 1, "LunarG Validation Layer",
191e11120777bcd1543455d1de54b89292879bcd2bbChia-I Wu};
1925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
193cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskitemplate <class TCreateInfo>
194cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskivoid ValidateLayerOrdering(const TCreateInfo &createInfo) {
1955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool foundLayer = false;
1965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < createInfo.enabledLayerCount; ++i) {
197e11120777bcd1543455d1de54b89292879bcd2bbChia-I Wu        if (!strcmp(createInfo.ppEnabledLayerNames[i], global_layer.layerName)) {
1985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            foundLayer = true;
1995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
2005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // This has to be logged to console as we don't have a callback at this point.
2015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!foundLayer && !strcmp(createInfo.ppEnabledLayerNames[0], "VK_LAYER_GOOGLE_unique_objects")) {
202bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            LOGCONSOLE("Cannot activate layer VK_LAYER_GOOGLE_unique_objects prior to activating %s.", global_layer.layerName);
2035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
2045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
2065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Code imported from shader_checker
2085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic void build_def_index(shader_module *);
2095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// A forward iterator over spirv instructions. Provides easy access to len, opcode, and content words
2115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// without the caller needing to care too much about the physical SPIRV module layout.
2125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstruct spirv_inst_iter {
2135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<uint32_t>::const_iterator zero;
2145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<uint32_t>::const_iterator it;
2155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
216b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes    uint32_t len() {
217b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes        auto result = *it >> 16;
218b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes        assert(result > 0);
219b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes        return result;
220b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes    }
221b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes
2225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t opcode() { return *it & 0x0ffffu; }
223b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes
224b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes    uint32_t const &word(unsigned n) {
225b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes        assert(n < len());
226b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes        return it[n];
227b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes    }
228b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes
2295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t offset() { return (uint32_t)(it - zero); }
2305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter() {}
2325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter(std::vector<uint32_t>::const_iterator zero, std::vector<uint32_t>::const_iterator it) : zero(zero), it(it) {}
2345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool operator==(spirv_inst_iter const &other) { return it == other.it; }
2365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool operator!=(spirv_inst_iter const &other) { return it != other.it; }
2385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
239cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    spirv_inst_iter operator++(int) {  // x++
2405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        spirv_inst_iter ii = *this;
2415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        it += len();
2425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return ii;
2435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
245cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    spirv_inst_iter operator++() {  // ++x;
2465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        it += len();
2475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return *this;
2485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
25025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // The iterator and the value are the same thing.
2515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter &operator*() { return *this; }
2525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter const &operator*() const { return *this; }
2535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis};
2545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstruct shader_module {
25625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // The spirv image itself
2575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    vector<uint32_t> words;
25825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // A mapping of <id> to the first word of its def. this is useful because walking type
25925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // trees, constant expressions, etc requires jumping all over the instruction stream.
2605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<unsigned, unsigned> def_index;
2615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    shader_module(VkShaderModuleCreateInfo const *pCreateInfo)
2635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        : words((uint32_t *)pCreateInfo->pCode, (uint32_t *)pCreateInfo->pCode + pCreateInfo->codeSize / sizeof(uint32_t)),
2645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis          def_index() {
2655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        build_def_index(this);
2665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
26825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Expose begin() / end() to enable range-based for
269cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    spirv_inst_iter begin() const { return spirv_inst_iter(words.begin(), words.begin() + 5); }  // First insn
270cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    spirv_inst_iter end() const { return spirv_inst_iter(words.begin(), words.end()); }          // Just past last insn
27125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Given an offset into the module, produce an iterator there.
2725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter at(unsigned offset) const { return spirv_inst_iter(words.begin(), words.begin() + offset); }
2735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Gets an iterator to the definition of an id
2755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter get_def(unsigned id) const {
2765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto it = def_index.find(id);
2775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (it == def_index.end()) {
2785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return end();
2795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
2805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return at(it->second);
2815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis};
2835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// TODO : This can be much smarter, using separate locks for separate global data
285b9e992386a44404152747d66817a733aa127e281Jeremy Hayesstatic std::mutex global_lock;
286593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
28779fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis// Return IMAGE_VIEW_STATE ptr for specified imageView or else NULL
28879fde938178535f598e030a0e9d19a0cb61b72e0Tobin EhlisIMAGE_VIEW_STATE *getImageViewState(const layer_data *dev_data, VkImageView image_view) {
2892c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    auto iv_it = dev_data->imageViewMap.find(image_view);
2902c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    if (iv_it == dev_data->imageViewMap.end()) {
2912c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis        return nullptr;
2922c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    }
2932c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    return iv_it->second.get();
2942c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis}
2959a55ca3674bb3fac3fbdfca9515a16a224aa9055Tobin Ehlis// Return sampler node ptr for specified sampler or else NULL
296d31a44af6da568692a73201825459689c9431867Tobin EhlisSAMPLER_STATE *getSamplerState(const layer_data *dev_data, VkSampler sampler) {
2972c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    auto sampler_it = dev_data->samplerMap.find(sampler);
2982c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    if (sampler_it == dev_data->samplerMap.end()) {
2999a55ca3674bb3fac3fbdfca9515a16a224aa9055Tobin Ehlis        return nullptr;
3009a55ca3674bb3fac3fbdfca9515a16a224aa9055Tobin Ehlis    }
3019a55ca3674bb3fac3fbdfca9515a16a224aa9055Tobin Ehlis    return sampler_it->second.get();
3029a55ca3674bb3fac3fbdfca9515a16a224aa9055Tobin Ehlis}
3035cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis// Return image state ptr for specified image or else NULL
3041facd2c91911508b9fb61f54a56269841299f663Tobin EhlisIMAGE_STATE *getImageState(const layer_data *dev_data, VkImage image) {
3056d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis    auto img_it = dev_data->imageMap.find(image);
3066d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis    if (img_it == dev_data->imageMap.end()) {
3076d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis        return nullptr;
3086d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis    }
3096d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis    return img_it->second.get();
3106d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis}
3115cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis// Return buffer state ptr for specified buffer or else NULL
3125cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin EhlisBUFFER_STATE *getBufferState(const layer_data *dev_data, VkBuffer buffer) {
3132c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    auto buff_it = dev_data->bufferMap.find(buffer);
3142c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    if (buff_it == dev_data->bufferMap.end()) {
3158718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis        return nullptr;
3168718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis    }
3178718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis    return buff_it->second.get();
3188718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis}
319b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis// Return swapchain node for specified swapchain or else NULL
320a682b1c533d9a492243b363c6585c4f03bcd87aaTobin EhlisSWAPCHAIN_NODE *getSwapchainNode(const layer_data *dev_data, VkSwapchainKHR swapchain) {
321b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis    auto swp_it = dev_data->device_extensions.swapchainMap.find(swapchain);
322b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis    if (swp_it == dev_data->device_extensions.swapchainMap.end()) {
323b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis        return nullptr;
324b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis    }
3253f687bf405355f3eec6bd1bc0e8d04daba37a0f9Tobin Ehlis    return swp_it->second.get();
326b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis}
327170dc65b45f6bcdec47e02b3aa19435e55b32804Tobin Ehlis// Return swapchain for specified image or else NULL
328a682b1c533d9a492243b363c6585c4f03bcd87aaTobin EhlisVkSwapchainKHR getSwapchainFromImage(const layer_data *dev_data, VkImage image) {
329170dc65b45f6bcdec47e02b3aa19435e55b32804Tobin Ehlis    auto img_it = dev_data->device_extensions.imageToSwapchainMap.find(image);
330170dc65b45f6bcdec47e02b3aa19435e55b32804Tobin Ehlis    if (img_it == dev_data->device_extensions.imageToSwapchainMap.end()) {
331170dc65b45f6bcdec47e02b3aa19435e55b32804Tobin Ehlis        return VK_NULL_HANDLE;
332170dc65b45f6bcdec47e02b3aa19435e55b32804Tobin Ehlis    }
333170dc65b45f6bcdec47e02b3aa19435e55b32804Tobin Ehlis    return img_it->second;
334170dc65b45f6bcdec47e02b3aa19435e55b32804Tobin Ehlis}
3352f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis// Return buffer node ptr for specified buffer or else NULL
33639267c0c27b8f032f05a6747eb02d4508247fdc1Tobin EhlisBUFFER_VIEW_STATE *getBufferViewState(const layer_data *my_data, VkBufferView buffer_view) {
3372f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis    auto bv_it = my_data->bufferViewMap.find(buffer_view);
3382f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis    if (bv_it == my_data->bufferViewMap.end()) {
3392f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis        return nullptr;
3402f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis    }
3412f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis    return bv_it->second.get();
3422f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis}
3438718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis
34466fb98d19a758f79dd11ba354e47d0c66c6aac1eChris ForbesFENCE_NODE *getFenceNode(layer_data *dev_data, VkFence fence) {
34566fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    auto it = dev_data->fenceMap.find(fence);
34666fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    if (it == dev_data->fenceMap.end()) {
34766fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes        return nullptr;
34866fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    }
34966fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    return &it->second;
35066fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes}
35166fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes
3524710dda89a1dd2e023334d4eda710a394b211cdcTobin EhlisEVENT_STATE *getEventNode(layer_data *dev_data, VkEvent event) {
3539556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis    auto it = dev_data->eventMap.find(event);
3549556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis    if (it == dev_data->eventMap.end()) {
3559556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis        return nullptr;
3569556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis    }
3579556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis    return &it->second;
3589556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis}
3599556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis
360ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin EhlisQUERY_POOL_NODE *getQueryPoolNode(layer_data *dev_data, VkQueryPool query_pool) {
361ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    auto it = dev_data->queryPoolMap.find(query_pool);
362ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    if (it == dev_data->queryPoolMap.end()) {
363ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis        return nullptr;
364ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    }
365ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    return &it->second;
366ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis}
367ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis
36836c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin EhlisQUEUE_STATE *getQueueState(layer_data *dev_data, VkQueue queue) {
36966fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    auto it = dev_data->queueMap.find(queue);
37066fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    if (it == dev_data->queueMap.end()) {
37166fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes        return nullptr;
37266fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    }
37366fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    return &it->second;
37466fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes}
37566fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes
3765e92f3cfdca6a52a3dcefd053c41f728bd036cebChris ForbesSEMAPHORE_NODE *getSemaphoreNode(layer_data *dev_data, VkSemaphore semaphore) {
3775e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes    auto it = dev_data->semaphoreMap.find(semaphore);
3785e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes    if (it == dev_data->semaphoreMap.end()) {
3795e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes        return nullptr;
3805e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes    }
3815e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes    return &it->second;
3825e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes}
3835e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes
3848d6a38de0389036581ada119e548180c614fe0efChris ForbesCOMMAND_POOL_NODE *getCommandPoolNode(layer_data *dev_data, VkCommandPool pool) {
3858d6a38de0389036581ada119e548180c614fe0efChris Forbes    auto it = dev_data->commandPoolMap.find(pool);
3868d6a38de0389036581ada119e548180c614fe0efChris Forbes    if (it == dev_data->commandPoolMap.end()) {
3878d6a38de0389036581ada119e548180c614fe0efChris Forbes        return nullptr;
3888d6a38de0389036581ada119e548180c614fe0efChris Forbes    }
3898d6a38de0389036581ada119e548180c614fe0efChris Forbes    return &it->second;
3908d6a38de0389036581ada119e548180c614fe0efChris Forbes}
3913bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes
392f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris ForbesPHYSICAL_DEVICE_STATE *getPhysicalDeviceState(instance_layer_data *instance_data, VkPhysicalDevice phys) {
393f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes    auto it = instance_data->physical_device_map.find(phys);
394f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes    if (it == instance_data->physical_device_map.end()) {
3953bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes        return nullptr;
3963bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes    }
3973bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes    return &it->second;
3983bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes}
3993bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes
400747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesSURFACE_STATE *getSurfaceState(instance_layer_data *instance_data, VkSurfaceKHR surface) {
401747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    auto it = instance_data->surface_map.find(surface);
402747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    if (it == instance_data->surface_map.end()) {
403747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        return nullptr;
404747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
405747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return &it->second;
406747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
407747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
408f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis// Return ptr to memory binding for given handle of specified type
409f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlisstatic BINDABLE *GetObjectMemBinding(layer_data *my_data, uint64_t handle, VkDebugReportObjectTypeEXT type) {
4105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (type) {
411cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT:
412cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return getImageState(my_data, VkImage(handle));
413cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT:
414cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return getBufferState(my_data, VkBuffer(handle));
415cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
416cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
4175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
41894c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis    return nullptr;
4195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
42072d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis// prototype
4215121a8dcacb23766ba4455b4eea429f0a3d62099Chris Forbesstatic GLOBAL_CB_NODE *getCBNode(layer_data const *, const VkCommandBuffer);
42272d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis
4235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Helper function to validate correct usage bits set for buffers or images
4245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Verify that (actual & desired) flags != 0 or,
4255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//   if strict is true, verify that (actual & desired) flags == desired
4265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  In case of error, report it via dbg callbacks
4271b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayesstatic bool validate_usage_flags(layer_data *my_data, VkFlags actual, VkFlags desired, VkBool32 strict, uint64_t obj_handle,
4281b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes                                 VkDebugReportObjectTypeEXT obj_type, int32_t const msgCode, char const *ty_str,
4291b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes                                 char const *func_name, char const *usage_str) {
430e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool correct_usage = false;
43183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
4325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (strict)
4335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        correct_usage = ((actual & desired) == desired);
4345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    else
4355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        correct_usage = ((actual & desired) != 0);
4365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (!correct_usage) {
4371b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes        if (msgCode == -1) {
4381b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes            // TODO: Fix callers with msgCode == -1 to use correct validation checks.
4391b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes            skip_call =
4401b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes                log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, obj_type, obj_handle, __LINE__,
4411b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes                        MEMTRACK_INVALID_USAGE_FLAG, "MEM", "Invalid usage flag for %s 0x%" PRIxLEAST64
4421b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes                                                            " used by %s. In this case, %s should have %s set during creation.",
4431b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes                        ty_str, obj_handle, func_name, ty_str, usage_str);
4441b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes        } else {
4451b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes            const char *valid_usage = (msgCode == -1) ? "" : validation_error_map[msgCode];
4461b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes            skip_call = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, obj_type, obj_handle, __LINE__, msgCode, "MEM",
4471b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes                                "Invalid usage flag for %s 0x%" PRIxLEAST64
4481b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes                                " used by %s. In this case, %s should have %s set during creation. %s",
4491b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes                                ty_str, obj_handle, func_name, ty_str, usage_str, valid_usage);
4501b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes        }
4515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
45283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
4535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
4545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Helper function to validate usage flags for buffers
4565cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis// For given buffer_state send actual vs. desired usage off to helper above where
457249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis//  an error will be flagged if usage is not correct
4581facd2c91911508b9fb61f54a56269841299f663Tobin Ehlisstatic bool ValidateImageUsageFlags(layer_data *dev_data, IMAGE_STATE const *image_state, VkFlags desired, VkBool32 strict,
4591b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes                                    int32_t const msgCode, char const *func_name, char const *usage_string) {
4601facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    return validate_usage_flags(dev_data, image_state->createInfo.usage, desired, strict,
4611facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis                                reinterpret_cast<const uint64_t &>(image_state->image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4621b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes                                msgCode, "image", func_name, usage_string);
463249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis}
464249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis
465249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis// Helper function to validate usage flags for buffers
4665cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis// For given buffer_state send actual vs. desired usage off to helper above where
467ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis//  an error will be flagged if usage is not correct
4685cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlisstatic bool ValidateBufferUsageFlags(layer_data *dev_data, BUFFER_STATE const *buffer_state, VkFlags desired, VkBool32 strict,
4691b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes                                     int32_t const msgCode, char const *func_name, char const *usage_string) {
4705cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    return validate_usage_flags(dev_data, buffer_state->createInfo.usage, desired, strict,
4715cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis                                reinterpret_cast<const uint64_t &>(buffer_state->buffer), VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
4721b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes                                msgCode, "buffer", func_name, usage_string);
473ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis}
474ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
4755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Return ptr to info in map container containing mem, or NULL if not found
4765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Calls to this function should be wrapped in mutex
47757fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin EhlisDEVICE_MEM_INFO *getMemObjInfo(const layer_data *dev_data, const VkDeviceMemory mem) {
47857fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    auto mem_it = dev_data->memObjMap.find(mem);
47957fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    if (mem_it == dev_data->memObjMap.end()) {
4805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return NULL;
4815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
48257fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    return mem_it->second.get();
4835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
4845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic void add_mem_obj_info(layer_data *my_data, void *object, const VkDeviceMemory mem,
4865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                             const VkMemoryAllocateInfo *pAllocateInfo) {
4875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(object != NULL);
4885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
48957fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    my_data->memObjMap[mem] = unique_ptr<DEVICE_MEM_INFO>(new DEVICE_MEM_INFO(object, mem, pAllocateInfo));
4905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
491dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis
492dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis// Helper function to print lowercase string of object type
493dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis//  TODO: Unify string helper functions, this should really come out of a string helper if not there already
494dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlisstatic const char *object_type_to_string(VkDebugReportObjectTypeEXT type) {
495dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis    switch (type) {
496cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT:
497cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "image";
498cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT:
499cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "buffer";
500cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT:
501cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "image view";
502cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT:
503cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "buffer view";
504cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT:
505cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "swapchain";
506cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT:
507cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "descriptor set";
508cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT:
509cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "framebuffer";
510cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT:
511cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "event";
512cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT:
513cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "query pool";
514cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT:
515cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "descriptor pool";
516cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT:
517cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "command pool";
518cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT:
519cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "pipeline";
520cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT:
521cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "sampler";
522cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT:
523cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "renderpass";
524cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT:
525cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "device memory";
526cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT:
527cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "semaphore";
528cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
529cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "unknown";
530dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis    }
531dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis}
532dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis
533cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis// For given bound_object_handle, bound to given mem allocation, verify that the range for the bound object is valid
534f989de4217bce0f293121d0da53dc8328276370fTobin Ehlisstatic bool ValidateMemoryIsValid(layer_data *dev_data, VkDeviceMemory mem, uint64_t bound_object_handle,
535dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis                                  VkDebugReportObjectTypeEXT type, const char *functionName) {
536f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    DEVICE_MEM_INFO *mem_info = getMemObjInfo(dev_data, mem);
537f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    if (mem_info) {
538f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis        if (!mem_info->bound_ranges[bound_object_handle].valid) {
539f48a83f5b5548cd46a12770c7542ff902537ad3eKarl Schultz            return log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
540ea8e85ade623a09c601d939622cbd7740d8d66c9Tobin Ehlis                           reinterpret_cast<uint64_t &>(mem), __LINE__, MEMTRACK_INVALID_MEM_REGION, "MEM",
541dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis                           "%s: Cannot read invalid region of memory allocation 0x%" PRIx64 " for bound %s object 0x%" PRIx64
542dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis                           ", please fill the memory before using.",
543dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis                           functionName, reinterpret_cast<uint64_t &>(mem), object_type_to_string(type), bound_object_handle);
544f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis        }
545f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    }
546f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    return false;
547f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis}
5481facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis// For given image_state
5491facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis//  If mem is special swapchain key, then verify that image_state valid member is true
550f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis//  Else verify that the image's bound memory range is valid
5511facd2c91911508b9fb61f54a56269841299f663Tobin Ehlisstatic bool ValidateImageMemoryIsValid(layer_data *dev_data, IMAGE_STATE *image_state, const char *functionName) {
552e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis    if (image_state->binding.mem == MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
5531facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        if (!image_state->valid) {
554f48a83f5b5548cd46a12770c7542ff902537ad3eKarl Schultz            return log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
555e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis                           reinterpret_cast<uint64_t &>(image_state->binding.mem), __LINE__, MEMTRACK_INVALID_MEM_REGION, "MEM",
556414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                           "%s: Cannot read invalid swapchain image 0x%" PRIx64 ", please fill the memory before using.",
5571facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis                           functionName, reinterpret_cast<uint64_t &>(image_state->image));
5585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
5595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
560e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis        return ValidateMemoryIsValid(dev_data, image_state->binding.mem, reinterpret_cast<uint64_t &>(image_state->image),
561dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis                                     VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, functionName);
5625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return false;
5645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
5655cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis// For given buffer_state, verify that the range it's bound to is valid
5665cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlisstatic bool ValidateBufferMemoryIsValid(layer_data *dev_data, BUFFER_STATE *buffer_state, const char *functionName) {
5675cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    return ValidateMemoryIsValid(dev_data, buffer_state->binding.mem, reinterpret_cast<uint64_t &>(buffer_state->buffer),
568dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis                                 VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, functionName);
569f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis}
570f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis// For the given memory allocation, set the range bound by the given handle object to the valid param value
571f989de4217bce0f293121d0da53dc8328276370fTobin Ehlisstatic void SetMemoryValid(layer_data *dev_data, VkDeviceMemory mem, uint64_t handle, bool valid) {
572f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    DEVICE_MEM_INFO *mem_info = getMemObjInfo(dev_data, mem);
573f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    if (mem_info) {
574f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis        mem_info->bound_ranges[handle].valid = valid;
575f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    }
576f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis}
577f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis// For given image node
5781facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis//  If mem is special swapchain key, then set entire image_state to valid param value
579f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis//  Else set the image's bound memory range to valid param value
5801facd2c91911508b9fb61f54a56269841299f663Tobin Ehlisstatic void SetImageMemoryValid(layer_data *dev_data, IMAGE_STATE *image_state, bool valid) {
581e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis    if (image_state->binding.mem == MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
5821facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        image_state->valid = valid;
5835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
584e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis        SetMemoryValid(dev_data, image_state->binding.mem, reinterpret_cast<uint64_t &>(image_state->image), valid);
5855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
587f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis// For given buffer node set the buffer's bound memory range to valid param value
5885cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlisstatic void SetBufferMemoryValid(layer_data *dev_data, BUFFER_STATE *buffer_state, bool valid) {
5895cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    SetMemoryValid(dev_data, buffer_state->binding.mem, reinterpret_cast<uint64_t &>(buffer_state->buffer), valid);
590f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis}
5915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Find CB Info and add mem reference to list container
5925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Find Mem Obj Info and add CB reference to list container
593e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool update_cmd_buf_and_mem_references(layer_data *dev_data, const VkCommandBuffer cb, const VkDeviceMemory mem,
594e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                                              const char *apiName) {
59583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
5965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Skip validation if this image was created through WSI
5985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (mem != MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
5995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // First update CB binding in MemObj mini CB list
60057fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        DEVICE_MEM_INFO *pMemInfo = getMemObjInfo(dev_data, mem);
6015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (pMemInfo) {
6025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Now update CBInfo's Mem reference list
603d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis            GLOBAL_CB_NODE *cb_node = getCBNode(dev_data, cb);
604d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis            pMemInfo->cb_bindings.insert(cb_node);
6055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // TODO: keep track of all destroyed CBs so we know if this is a stale or simply invalid object
606d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis            if (cb_node) {
607d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                cb_node->memObjs.insert(mem);
6085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
6095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
61183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
6125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
613ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
61456f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis// Create binding link between given sampler and command buffer node
615d31a44af6da568692a73201825459689c9431867Tobin Ehlisvoid AddCommandBufferBindingSampler(GLOBAL_CB_NODE *cb_node, SAMPLER_STATE *sampler_state) {
616d31a44af6da568692a73201825459689c9431867Tobin Ehlis    sampler_state->cb_bindings.insert(cb_node);
617d31a44af6da568692a73201825459689c9431867Tobin Ehlis    cb_node->object_bindings.insert(
618d31a44af6da568692a73201825459689c9431867Tobin Ehlis        {reinterpret_cast<uint64_t &>(sampler_state->sampler), VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT});
61956f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis}
62056f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis
62156f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis// Create binding link between given image node and command buffer node
6221facd2c91911508b9fb61f54a56269841299f663Tobin Ehlisvoid AddCommandBufferBindingImage(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, IMAGE_STATE *image_state) {
623ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    // Skip validation if this image was created through WSI
624e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis    if (image_state->binding.mem != MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
625ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // First update CB binding in MemObj mini CB list
626d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis        for (auto mem_binding : image_state->GetBoundMemory()) {
627d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            DEVICE_MEM_INFO *pMemInfo = getMemObjInfo(dev_data, mem_binding);
628d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            if (pMemInfo) {
629d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis                pMemInfo->cb_bindings.insert(cb_node);
630d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis                // Now update CBInfo's Mem reference list
631d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis                cb_node->memObjs.insert(mem_binding);
632d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            }
633ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        }
634f940225c9e5e3e14b3f5a32d3ea360b585614600Tobin Ehlis        // Now update cb binding for image
6351facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        cb_node->object_bindings.insert({reinterpret_cast<uint64_t &>(image_state->image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT});
6361facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        image_state->cb_bindings.insert(cb_node);
637ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    }
638ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis}
639ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
64003ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis// Create binding link between given image view node and its image with command buffer node
64103ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlisvoid AddCommandBufferBindingImageView(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, IMAGE_VIEW_STATE *view_state) {
64203ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis    // First add bindings for imageView
64303ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis    view_state->cb_bindings.insert(cb_node);
64403ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis    cb_node->object_bindings.insert(
64503ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis        {reinterpret_cast<uint64_t &>(view_state->image_view), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT});
6461facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    auto image_state = getImageState(dev_data, view_state->create_info.image);
64703ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis    // Add bindings for image within imageView
6481facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (image_state) {
6491facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        AddCommandBufferBindingImage(dev_data, cb_node, image_state);
65003ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis    }
65103ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis}
65203ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis
653ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis// Create binding link between given buffer node and command buffer node
6545cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlisvoid AddCommandBufferBindingBuffer(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, BUFFER_STATE *buffer_state) {
655ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    // First update CB binding in MemObj mini CB list
6565cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    for (auto mem_binding : buffer_state->GetBoundMemory()) {
657d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis        DEVICE_MEM_INFO *pMemInfo = getMemObjInfo(dev_data, mem_binding);
658d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis        if (pMemInfo) {
659d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            pMemInfo->cb_bindings.insert(cb_node);
660d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            // Now update CBInfo's Mem reference list
661d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            cb_node->memObjs.insert(mem_binding);
662d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis        }
663ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    }
664ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    // Now update cb binding for buffer
6655cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    cb_node->object_bindings.insert({reinterpret_cast<uint64_t &>(buffer_state->buffer), VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT});
6665cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    buffer_state->cb_bindings.insert(cb_node);
667ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis}
668ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
66977b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis// Create binding link between given buffer view node and its buffer with command buffer node
67077b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlisvoid AddCommandBufferBindingBufferView(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, BUFFER_VIEW_STATE *view_state) {
67177b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis    // First add bindings for bufferView
67277b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis    view_state->cb_bindings.insert(cb_node);
67377b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis    cb_node->object_bindings.insert(
67477b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis        {reinterpret_cast<uint64_t &>(view_state->buffer_view), VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT});
6755cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    auto buffer_state = getBufferState(dev_data, view_state->create_info.buffer);
67677b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis    // Add bindings for buffer within bufferView
6775cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (buffer_state) {
6785cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        AddCommandBufferBindingBuffer(dev_data, cb_node, buffer_state);
67977b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis    }
68077b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis}
68177b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis
682400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis// For every mem obj bound to particular CB, free bindings related to that CB
683d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlisstatic void clear_cmd_buf_and_mem_references(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
684d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis    if (cb_node) {
685d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis        if (cb_node->memObjs.size() > 0) {
686d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis            for (auto mem : cb_node->memObjs) {
68757fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis                DEVICE_MEM_INFO *pInfo = getMemObjInfo(dev_data, mem);
6885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (pInfo) {
689d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                    pInfo->cb_bindings.erase(cb_node);
6905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
6915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
692d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis            cb_node->memObjs.clear();
6935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
694d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis        cb_node->validate_functions.clear();
6955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
697400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis// Overloaded call to above function when GLOBAL_CB_NODE has not already been looked-up
698400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlisstatic void clear_cmd_buf_and_mem_references(layer_data *dev_data, const VkCommandBuffer cb) {
699400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis    clear_cmd_buf_and_mem_references(dev_data, getCBNode(dev_data, cb));
7005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
7015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
702f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis// Clear a single object binding from given memory object, or report error if binding is missing
703f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlisstatic bool ClearMemoryObjectBinding(layer_data *dev_data, uint64_t handle, VkDebugReportObjectTypeEXT type, VkDeviceMemory mem) {
704f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    DEVICE_MEM_INFO *mem_info = getMemObjInfo(dev_data, mem);
705f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    // This obj is bound to a memory object. Remove the reference to this object in that memory object's list
706d4cd34fd49caa759cf01cafa5fa271401b17c3b9Jeremy Hayes    if (mem_info) {
707d4cd34fd49caa759cf01cafa5fa271401b17c3b9Jeremy Hayes        mem_info->obj_bindings.erase({handle, type});
708f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    }
709f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    return false;
710f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis}
711f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis
712f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis// ClearMemoryObjectBindings clears the binding of objects to memory
713f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis//  For the given object it pulls the memory bindings and makes sure that the bindings
714f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis//  no longer refer to the object being cleared. This occurs when objects are destroyed.
715f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlisstatic bool ClearMemoryObjectBindings(layer_data *dev_data, uint64_t handle, VkDebugReportObjectTypeEXT type) {
716f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    bool skip = false;
717f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    BINDABLE *mem_binding = GetObjectMemBinding(dev_data, handle, type);
718f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    if (mem_binding) {
719f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        if (!mem_binding->sparse) {
720f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis            skip = ClearMemoryObjectBinding(dev_data, handle, type, mem_binding->binding.mem);
721cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        } else {  // Sparse, clear all bindings
722bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            for (auto &sparse_mem_binding : mem_binding->sparse_bindings) {
723f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                skip |= ClearMemoryObjectBinding(dev_data, handle, type, sparse_mem_binding.mem);
7245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
7255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
727f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    return skip;
7285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
7295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
730888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis// For given mem object, verify that it is not null or UNBOUND, if it is, report error. Return skip value.
731888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlisbool VerifyBoundMemoryIsValid(const layer_data *dev_data, VkDeviceMemory mem, uint64_t handle, const char *api_name,
73235ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                              const char *type_name, UNIQUE_VALIDATION_ERROR_CODE error_code) {
733888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    bool result = false;
734888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    if (VK_NULL_HANDLE == mem) {
735888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis        result = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, handle,
736cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                         __LINE__, error_code, "MEM", "%s: Vk%s object 0x%" PRIxLEAST64
737cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                      " used with no memory bound. Memory should be bound by calling "
738cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                      "vkBind%sMemory(). %s",
73935ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                         api_name, type_name, handle, type_name, validation_error_map[error_code]);
740888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    } else if (MEMORY_UNBOUND == mem) {
741888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis        result = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, handle,
742cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                         __LINE__, error_code, "MEM", "%s: Vk%s object 0x%" PRIxLEAST64
743cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                      " used with no memory bound and previously bound memory was freed. "
744cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                      "Memory must not be freed prior to this operation. %s",
74535ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                         api_name, type_name, handle, validation_error_map[error_code]);
746888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    }
747888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    return result;
748888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis}
749888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis
750b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski// Check to see if memory was ever bound to this image
75135ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlisbool ValidateMemoryIsBoundToImage(const layer_data *dev_data, const IMAGE_STATE *image_state, const char *api_name,
75235ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                                  UNIQUE_VALIDATION_ERROR_CODE error_code) {
753b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    bool result = false;
7541facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (0 == (static_cast<uint32_t>(image_state->createInfo.flags) & VK_IMAGE_CREATE_SPARSE_BINDING_BIT)) {
75535ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis        result = VerifyBoundMemoryIsValid(dev_data, image_state->binding.mem,
75635ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                                          reinterpret_cast<const uint64_t &>(image_state->image), api_name, "Image", error_code);
757b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    }
758b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    return result;
759b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski}
760b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski
761b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski// Check to see if memory was bound to this buffer
76235ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlisbool ValidateMemoryIsBoundToBuffer(const layer_data *dev_data, const BUFFER_STATE *buffer_state, const char *api_name,
76335ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                                   UNIQUE_VALIDATION_ERROR_CODE error_code) {
764b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    bool result = false;
7655cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (0 == (static_cast<uint32_t>(buffer_state->createInfo.flags) & VK_BUFFER_CREATE_SPARSE_BINDING_BIT)) {
7665cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        result = VerifyBoundMemoryIsValid(dev_data, buffer_state->binding.mem,
76735ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                                          reinterpret_cast<const uint64_t &>(buffer_state->buffer), api_name, "Buffer", error_code);
768b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    }
769b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    return result;
770b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski}
771b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski
772f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis// SetMemBinding is used to establish immutable, non-sparse binding between a single image/buffer object and memory object
7735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// For NULL mem case, output warning
7745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Make sure given object is in global object map
7755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  IF a previous binding existed, output validation error
7765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Otherwise, add reference from objectInfo to memoryInfo
7775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Add reference off of objInfo
7784f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes// TODO: We may need to refactor or pass in multiple valid usage statements to handle multiple valid usage conditions.
779888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlisstatic bool SetMemBinding(layer_data *dev_data, VkDeviceMemory mem, uint64_t handle, VkDebugReportObjectTypeEXT type,
780888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                          const char *apiName) {
78183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
782f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    // It's an error to bind an object to NULL memory
783d3876b4ff7c293a14f73fe3622513d1fa91bf2d0Jeremy Hayes    if (mem != VK_NULL_HANDLE) {
784f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        BINDABLE *mem_binding = GetObjectMemBinding(dev_data, handle, type);
785888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis        assert(mem_binding);
786f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        // TODO : Add check here to make sure object isn't sparse
787f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        //  VALIDATION_ERROR_00792 for buffers
788f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        //  VALIDATION_ERROR_00804 for images
789f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        assert(!mem_binding->sparse);
790888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis        DEVICE_MEM_INFO *mem_info = getMemObjInfo(dev_data, mem);
791888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis        if (mem_info) {
792f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis            DEVICE_MEM_INFO *prev_binding = getMemObjInfo(dev_data, mem_binding->binding.mem);
793888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis            if (prev_binding) {
7944f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                // TODO: VALIDATION_ERROR_00791 and VALIDATION_ERROR_00803
795888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                skip_call |=
796888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
797888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                            reinterpret_cast<uint64_t &>(mem), __LINE__, MEMTRACK_REBIND_OBJECT, "MEM",
798888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                            "In %s, attempting to bind memory (0x%" PRIxLEAST64 ") to object (0x%" PRIxLEAST64
799888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                            ") which has already been bound to mem object 0x%" PRIxLEAST64,
800888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                            apiName, reinterpret_cast<uint64_t &>(mem), handle, reinterpret_cast<uint64_t &>(prev_binding->mem));
801f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis            } else if (mem_binding->binding.mem == MEMORY_UNBOUND) {
802888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                skip_call |=
803888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
804888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                            reinterpret_cast<uint64_t &>(mem), __LINE__, MEMTRACK_REBIND_OBJECT, "MEM",
805888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                            "In %s, attempting to bind memory (0x%" PRIxLEAST64 ") to object (0x%" PRIxLEAST64
806888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                            ") which was previous bound to memory that has since been freed. Memory bindings are immutable in "
807888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                            "Vulkan so this attempt to bind to new memory is not allowed.",
808888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                            apiName, reinterpret_cast<uint64_t &>(mem), handle);
8092e415b757c1e43fda35311aad026af8d5c96681cTobin Ehlis            } else {
810888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                mem_info->obj_bindings.insert({handle, type});
8112e415b757c1e43fda35311aad026af8d5c96681cTobin Ehlis                // For image objects, make sure default memory state is correctly set
8122e415b757c1e43fda35311aad026af8d5c96681cTobin Ehlis                // TODO : What's the best/correct way to handle this?
8132e415b757c1e43fda35311aad026af8d5c96681cTobin Ehlis                if (VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT == type) {
8141facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis                    auto const image_state = getImageState(dev_data, VkImage(handle));
8151facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis                    if (image_state) {
8161facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis                        VkImageCreateInfo ici = image_state->createInfo;
8172e415b757c1e43fda35311aad026af8d5c96681cTobin Ehlis                        if (ici.usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
8182e415b757c1e43fda35311aad026af8d5c96681cTobin Ehlis                            // TODO::  More memory state transition stuff.
8195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        }
8205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
8215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
822f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                mem_binding->binding.mem = mem;
8235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
8245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
82683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
8275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
8285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// For NULL mem case, clear any previous binding Else...
8305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Make sure given object is in its object map
8315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  IF a previous binding existed, update binding
8325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Add reference from objectInfo to memoryInfo
8335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Add reference off of object's binding info
8340a1ce3dfd81c9f4efbe46f5ba5ddaea70bc4aa61Chris Forbes// Return VK_TRUE if addition is successful, VK_FALSE otherwise
835f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlisstatic bool SetSparseMemBinding(layer_data *dev_data, MEM_BINDING binding, uint64_t handle, VkDebugReportObjectTypeEXT type,
836f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                                const char *apiName) {
83783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = VK_FALSE;
8385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Handle NULL case separately, just clear previous binding & decrement reference
839f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    if (binding.mem == VK_NULL_HANDLE) {
840f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        // TODO : This should cause the range of the resource to be unbound according to spec
8415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
842f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        BINDABLE *mem_binding = GetObjectMemBinding(dev_data, handle, type);
843f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        assert(mem_binding);
844f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        assert(mem_binding->sparse);
845f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        DEVICE_MEM_INFO *mem_info = getMemObjInfo(dev_data, binding.mem);
846f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        if (mem_info) {
847f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis            mem_info->obj_bindings.insert({handle, type});
8482e415b757c1e43fda35311aad026af8d5c96681cTobin Ehlis            // Need to set mem binding for this object
849f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis            mem_binding->sparse_bindings.insert(binding);
8505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
85283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
853caf05e0db4959ae196ab34b024f352d9c0326870Tobin Ehlis}
854caf05e0db4959ae196ab34b024f352d9c0326870Tobin Ehlis
8555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Return a string representation of CMD_TYPE enum
8565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic string cmdTypeToString(CMD_TYPE cmd) {
8575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (cmd) {
858cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_BINDPIPELINE:
859cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_BINDPIPELINE";
860cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_BINDPIPELINEDELTA:
861cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_BINDPIPELINEDELTA";
862cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETVIEWPORTSTATE:
863cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETVIEWPORTSTATE";
864cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETLINEWIDTHSTATE:
865cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETLINEWIDTHSTATE";
866cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETDEPTHBIASSTATE:
867cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETDEPTHBIASSTATE";
868cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETBLENDSTATE:
869cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETBLENDSTATE";
870cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETDEPTHBOUNDSSTATE:
871cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETDEPTHBOUNDSSTATE";
872cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETSTENCILREADMASKSTATE:
873cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETSTENCILREADMASKSTATE";
874cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETSTENCILWRITEMASKSTATE:
875cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETSTENCILWRITEMASKSTATE";
876cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETSTENCILREFERENCESTATE:
877cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETSTENCILREFERENCESTATE";
878cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_BINDDESCRIPTORSETS:
879cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_BINDDESCRIPTORSETS";
880cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_BINDINDEXBUFFER:
881cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_BINDINDEXBUFFER";
882cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_BINDVERTEXBUFFER:
883cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_BINDVERTEXBUFFER";
884cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_DRAW:
885cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_DRAW";
886cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_DRAWINDEXED:
887cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_DRAWINDEXED";
888cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_DRAWINDIRECT:
889cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_DRAWINDIRECT";
890cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_DRAWINDEXEDINDIRECT:
891cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_DRAWINDEXEDINDIRECT";
892cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_DISPATCH:
893cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_DISPATCH";
894cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_DISPATCHINDIRECT:
895cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_DISPATCHINDIRECT";
896cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_COPYBUFFER:
897cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_COPYBUFFER";
898cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_COPYIMAGE:
899cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_COPYIMAGE";
900cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_BLITIMAGE:
901cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_BLITIMAGE";
902cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_COPYBUFFERTOIMAGE:
903cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_COPYBUFFERTOIMAGE";
904cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_COPYIMAGETOBUFFER:
905cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_COPYIMAGETOBUFFER";
906cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_CLONEIMAGEDATA:
907cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_CLONEIMAGEDATA";
908cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_UPDATEBUFFER:
909cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_UPDATEBUFFER";
910cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_FILLBUFFER:
911cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_FILLBUFFER";
912cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_CLEARCOLORIMAGE:
913cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_CLEARCOLORIMAGE";
914cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_CLEARATTACHMENTS:
915cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_CLEARCOLORATTACHMENT";
916cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_CLEARDEPTHSTENCILIMAGE:
917cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_CLEARDEPTHSTENCILIMAGE";
918cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_RESOLVEIMAGE:
919cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_RESOLVEIMAGE";
920cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETEVENT:
921cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETEVENT";
922cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_RESETEVENT:
923cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_RESETEVENT";
924cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_WAITEVENTS:
925cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_WAITEVENTS";
926cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_PIPELINEBARRIER:
927cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_PIPELINEBARRIER";
928cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_BEGINQUERY:
929cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_BEGINQUERY";
930cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_ENDQUERY:
931cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_ENDQUERY";
932cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_RESETQUERYPOOL:
933cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_RESETQUERYPOOL";
934cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_COPYQUERYPOOLRESULTS:
935cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_COPYQUERYPOOLRESULTS";
936cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_WRITETIMESTAMP:
937cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_WRITETIMESTAMP";
938cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_INITATOMICCOUNTERS:
939cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_INITATOMICCOUNTERS";
940cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_LOADATOMICCOUNTERS:
941cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_LOADATOMICCOUNTERS";
942cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SAVEATOMICCOUNTERS:
943cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SAVEATOMICCOUNTERS";
944cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_BEGINRENDERPASS:
945cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_BEGINRENDERPASS";
946cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_ENDRENDERPASS:
947cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_ENDRENDERPASS";
948cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
949cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "UNKNOWN";
9505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
9525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// SPIRV utility functions
9545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic void build_def_index(shader_module *module) {
9555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *module) {
9565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        switch (insn.opcode()) {
957cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Types
958cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeVoid:
959cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeBool:
960cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeInt:
961cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeFloat:
962cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeVector:
963cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeMatrix:
964cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeImage:
965cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeSampler:
966cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeSampledImage:
967cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeArray:
968cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeRuntimeArray:
969cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeStruct:
970cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeOpaque:
971cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypePointer:
972cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeFunction:
973cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeEvent:
974cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeDeviceEvent:
975cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeReserveId:
976cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeQueue:
977cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypePipe:
978cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                module->def_index[insn.word(1)] = insn.offset();
979cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
9805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
981cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Fixed constants
982cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstantTrue:
983cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstantFalse:
984cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstant:
985cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstantComposite:
986cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstantSampler:
987cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstantNull:
988cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                module->def_index[insn.word(2)] = insn.offset();
989cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
9905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
991cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Specialization constants
992cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpSpecConstantTrue:
993cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpSpecConstantFalse:
994cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpSpecConstant:
995cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpSpecConstantComposite:
996cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpSpecConstantOp:
997cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                module->def_index[insn.word(2)] = insn.offset();
998cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
9995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1000cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Variables
1001cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpVariable:
1002cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                module->def_index[insn.word(2)] = insn.offset();
1003cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
10045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1005cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Functions
1006cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpFunction:
1007cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                module->def_index[insn.word(2)] = insn.offset();
1008cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
10095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1010cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
1011cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // We don't care about any other defs for now.
1012cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
10135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
10145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
10165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic spirv_inst_iter find_entrypoint(shader_module *src, char const *name, VkShaderStageFlagBits stageBits) {
10185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
10195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpEntryPoint) {
10205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            auto entrypointName = (char const *)&insn.word(3);
10215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            auto entrypointStageBits = 1u << insn.word(1);
10225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!strcmp(entrypointName, name) && (entrypointStageBits & stageBits)) {
10245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return insn;
10255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
10265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
10275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return src->end();
10305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
10315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic char const *storage_class_name(unsigned sc) {
10335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (sc) {
1034cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassInput:
1035cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "input";
1036cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassOutput:
1037cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "output";
1038cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassUniformConstant:
1039cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "const uniform";
1040cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassUniform:
1041cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "uniform";
1042cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassWorkgroup:
1043cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "workgroup local";
1044cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassCrossWorkgroup:
1045cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "workgroup global";
1046cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassPrivate:
1047cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "private global";
1048cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassFunction:
1049cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "function";
1050cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassGeneric:
1051cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "generic";
1052cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassAtomicCounter:
1053cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "atomic counter";
1054cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassImage:
1055cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "image";
1056cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassPushConstant:
1057cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "push constant";
1058cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1059cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "unknown";
10605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
10625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
106325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// Get the value of an integral constant
10645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisunsigned get_constant_value(shader_module const *src, unsigned id) {
10655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto value = src->get_def(id);
10665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(value != src->end());
10675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (value.opcode() != spv::OpConstant) {
106925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // TODO: Either ensure that the specialization transform is already performed on a module we're
107025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        //       considering here, OR -- specialize on the fly now.
10715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return 1;
10725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return value.word(3);
10755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
10765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10779ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbesstatic void describe_type_inner(std::ostringstream &ss, shader_module const *src, unsigned type) {
10785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto insn = src->get_def(type);
10795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(insn != src->end());
10805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (insn.opcode()) {
1082cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeBool:
1083cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "bool";
1084cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1085cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeInt:
1086cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << (insn.word(3) ? 's' : 'u') << "int" << insn.word(2);
1087cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1088cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeFloat:
1089cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "float" << insn.word(2);
1090cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1091cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeVector:
1092cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "vec" << insn.word(3) << " of ";
1093cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            describe_type_inner(ss, src, insn.word(2));
1094cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1095cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeMatrix:
1096cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "mat" << insn.word(3) << " of ";
1097cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            describe_type_inner(ss, src, insn.word(2));
1098cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1099cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeArray:
1100cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "arr[" << get_constant_value(src, insn.word(3)) << "] of ";
1101cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            describe_type_inner(ss, src, insn.word(2));
1102cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1103cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypePointer:
1104cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "ptr to " << storage_class_name(insn.word(2)) << " ";
1105cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            describe_type_inner(ss, src, insn.word(3));
1106cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1107cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeStruct: {
1108cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "struct of (";
1109cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            for (unsigned i = 2; i < insn.len(); i++) {
1110cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                describe_type_inner(ss, src, insn.word(i));
1111cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (i == insn.len() - 1) {
1112cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    ss << ")";
1113cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                } else {
1114cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    ss << ", ";
1115cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
11169ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes            }
1117cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
11185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
1119cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeSampler:
1120cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "sampler";
1121cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1122cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeSampledImage:
1123cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "sampler+";
1124cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            describe_type_inner(ss, src, insn.word(2));
1125cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1126cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeImage:
1127cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "image(dim=" << insn.word(3) << ", sampled=" << insn.word(7) << ")";
1128cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1129cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1130cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "oddtype";
1131cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
11325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
11335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
11345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11359ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbesstatic std::string describe_type(shader_module const *src, unsigned type) {
11369ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes    std::ostringstream ss;
11379ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes    describe_type_inner(ss, src, type);
11389ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes    return ss.str();
11399ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes}
11409ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes
1141bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool is_narrow_numeric_type(spirv_inst_iter type) {
1142cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (type.opcode() != spv::OpTypeInt && type.opcode() != spv::OpTypeFloat) return false;
114337576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes    return type.word(2) < 64;
114437576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes}
114537576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes
1146bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool types_match(shader_module const *a, shader_module const *b, unsigned a_type, unsigned b_type, bool a_arrayed,
1147bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        bool b_arrayed, bool relaxed) {
114825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Walk two type trees together, and complain about differences
11495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto a_insn = a->get_def(a_type);
11505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto b_insn = b->get_def(b_type);
11515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(a_insn != a->end());
11525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(b_insn != b->end());
11535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11547c755c8aca6857046df9516d8336416165969cb9Chris Forbes    if (a_arrayed && a_insn.opcode() == spv::OpTypeArray) {
115537576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes        return types_match(a, b, a_insn.word(2), b_type, false, b_arrayed, relaxed);
11567c755c8aca6857046df9516d8336416165969cb9Chris Forbes    }
11577c755c8aca6857046df9516d8336416165969cb9Chris Forbes
11585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (b_arrayed && b_insn.opcode() == spv::OpTypeArray) {
115925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // We probably just found the extra level of arrayness in b_type: compare the type inside it to a_type
116037576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes        return types_match(a, b, a_type, b_insn.word(2), a_arrayed, false, relaxed);
116137576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes    }
116237576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes
116337576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes    if (a_insn.opcode() == spv::OpTypeVector && relaxed && is_narrow_numeric_type(b_insn)) {
116437576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes        return types_match(a, b, a_insn.word(2), b_type, a_arrayed, b_arrayed, false);
11655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
11665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (a_insn.opcode() != b_insn.opcode()) {
11685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return false;
11695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
11705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11717c755c8aca6857046df9516d8336416165969cb9Chris Forbes    if (a_insn.opcode() == spv::OpTypePointer) {
117225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Match on pointee type. storage class is expected to differ
117337576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes        return types_match(a, b, a_insn.word(3), b_insn.word(3), a_arrayed, b_arrayed, relaxed);
11747c755c8aca6857046df9516d8336416165969cb9Chris Forbes    }
11757c755c8aca6857046df9516d8336416165969cb9Chris Forbes
11767c755c8aca6857046df9516d8336416165969cb9Chris Forbes    if (a_arrayed || b_arrayed) {
117725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // If we havent resolved array-of-verts by here, we're not going to.
11787c755c8aca6857046df9516d8336416165969cb9Chris Forbes        return false;
11797c755c8aca6857046df9516d8336416165969cb9Chris Forbes    }
11807c755c8aca6857046df9516d8336416165969cb9Chris Forbes
11815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (a_insn.opcode()) {
1182cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeBool:
1183cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return true;
1184cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeInt:
1185cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on width, signedness
1186cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return a_insn.word(2) == b_insn.word(2) && a_insn.word(3) == b_insn.word(3);
1187cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeFloat:
1188cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on width
1189cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return a_insn.word(2) == b_insn.word(2);
1190cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeVector:
1191cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on element type, count.
1192cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (!types_match(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false)) return false;
1193cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (relaxed && is_narrow_numeric_type(a->get_def(a_insn.word(2)))) {
1194cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return a_insn.word(3) >= b_insn.word(3);
1195cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else {
1196cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return a_insn.word(3) == b_insn.word(3);
11975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
1198cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeMatrix:
1199cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on element type, count.
1200cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return types_match(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false) &&
1201cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                   a_insn.word(3) == b_insn.word(3);
1202cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeArray:
1203cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on element type, count. these all have the same layout. we don't get here if b_arrayed. This differs from
1204cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // vector & matrix types in that the array size is the id of a constant instruction, * not a literal within OpTypeArray
1205cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return types_match(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false) &&
1206cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                   get_constant_value(a, a_insn.word(3)) == get_constant_value(b, b_insn.word(3));
1207cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeStruct:
1208cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on all element types
1209cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            {
1210cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (a_insn.len() != b_insn.len()) {
1211cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    return false;  // Structs cannot match if member counts differ
1212cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
12135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1214cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                for (unsigned i = 2; i < a_insn.len(); i++) {
1215cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    if (!types_match(a, b, a_insn.word(i), b_insn.word(i), a_arrayed, b_arrayed, false)) {
1216cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return false;
1217cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    }
1218cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
1219cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski
1220cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return true;
1221cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
1222cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1223cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Remaining types are CLisms, or may not appear in the interfaces we are interested in. Just claim no match.
1224cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return false;
12255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
12265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
12275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic int value_or_default(std::unordered_map<unsigned, unsigned> const &map, unsigned id, int def) {
12295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto it = map.find(id);
12305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (it == map.end())
12315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return def;
12325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    else
12335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return it->second;
12345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
12355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic unsigned get_locations_consumed_by_type(shader_module const *src, unsigned type, bool strip_array_level) {
12375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto insn = src->get_def(type);
12385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(insn != src->end());
12395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (insn.opcode()) {
1241cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypePointer:
1242cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // See through the ptr -- this is only ever at the toplevel for graphics shaders we're never actually passing
1243cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // pointers around.
1244cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_locations_consumed_by_type(src, insn.word(3), strip_array_level);
1245cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeArray:
1246cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (strip_array_level) {
1247cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return get_locations_consumed_by_type(src, insn.word(2), false);
1248cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else {
1249cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return get_constant_value(src, insn.word(3)) * get_locations_consumed_by_type(src, insn.word(2), false);
1250cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
1251cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeMatrix:
1252cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Num locations is the dimension * element size
1253cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return insn.word(3) * get_locations_consumed_by_type(src, insn.word(2), false);
1254cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeVector: {
1255cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            auto scalar_type = src->get_def(insn.word(2));
1256cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            auto bit_width =
1257cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                (scalar_type.opcode() == spv::OpTypeInt || scalar_type.opcode() == spv::OpTypeFloat) ? scalar_type.word(2) : 32;
1258cc52143fc093e1e62d2dacc4abc3966e04b6f6d6Chris Forbes
1259cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Locations are 128-bit wide; 3- and 4-component vectors of 64 bit types require two.
1260cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return (bit_width * insn.word(3) + 127) / 128;
1261cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
1262cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1263cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Everything else is just 1.
1264cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return 1;
12655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1266cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // TODO: extend to handle 64bit scalar types, whose vectors may need multiple locations.
12675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
12685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
12695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1270c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbesstatic unsigned get_locations_consumed_by_format(VkFormat format) {
1271c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes    switch (format) {
1272cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64A64_SFLOAT:
1273cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64A64_SINT:
1274cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64A64_UINT:
1275cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64_SFLOAT:
1276cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64_SINT:
1277cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64_UINT:
1278cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return 2;
1279cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1280cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return 1;
1281c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes    }
1282c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes}
1283c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes
12845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlistypedef std::pair<unsigned, unsigned> location_t;
12855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlistypedef std::pair<unsigned, unsigned> descriptor_slot_t;
12865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstruct interface_var {
12885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t id;
12895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t type_id;
12905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t offset;
1291b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes    bool is_patch;
1292fff9393206f66a154438e16fa0562c989f425498Chris Forbes    bool is_block_member;
1293b0436668e6594b8528e96de7bed208399fb2431dChris Forbes    bool is_relaxed_precision;
129425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // TODO: collect the name, too? Isn't required to be present.
12955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis};
12965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1297031261d21af8907953dd763398ce9a23e65b8749Chris Forbesstruct shader_stage_attributes {
1298031261d21af8907953dd763398ce9a23e65b8749Chris Forbes    char const *const name;
1299031261d21af8907953dd763398ce9a23e65b8749Chris Forbes    bool arrayed_input;
1300031261d21af8907953dd763398ce9a23e65b8749Chris Forbes    bool arrayed_output;
1301031261d21af8907953dd763398ce9a23e65b8749Chris Forbes};
1302031261d21af8907953dd763398ce9a23e65b8749Chris Forbes
1303031261d21af8907953dd763398ce9a23e65b8749Chris Forbesstatic shader_stage_attributes shader_stage_attribs[] = {
1304bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    {"vertex shader", false, false},  {"tessellation control shader", true, true}, {"tessellation evaluation shader", true, false},
1305bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    {"geometry shader", true, false}, {"fragment shader", false, false},
1306031261d21af8907953dd763398ce9a23e65b8749Chris Forbes};
1307031261d21af8907953dd763398ce9a23e65b8749Chris Forbes
13085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic spirv_inst_iter get_struct_type(shader_module const *src, spirv_inst_iter def, bool is_array_of_verts) {
13095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while (true) {
13105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (def.opcode() == spv::OpTypePointer) {
13115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            def = src->get_def(def.word(3));
13125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (def.opcode() == spv::OpTypeArray && is_array_of_verts) {
13135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            def = src->get_def(def.word(2));
13145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            is_array_of_verts = false;
13155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (def.opcode() == spv::OpTypeStruct) {
13165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return def;
13175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
13185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return src->end();
13195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
13205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
13215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
13225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1323bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic void collect_interface_block_members(shader_module const *src, std::map<location_t, interface_var> *out,
13245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                            std::unordered_map<unsigned, unsigned> const &blocks, bool is_array_of_verts,
1325b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes                                            uint32_t id, uint32_t type_id, bool is_patch) {
132625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Walk down the type_id presented, trying to determine whether it's actually an interface block.
1327031261d21af8907953dd763398ce9a23e65b8749Chris Forbes    auto type = get_struct_type(src, src->get_def(type_id), is_array_of_verts && !is_patch);
13285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (type == src->end() || blocks.find(type.word(1)) == blocks.end()) {
132925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // This isn't an interface block.
13305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return;
13315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
13325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> member_components;
13345b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes    std::unordered_map<unsigned, unsigned> member_relaxed_precision;
13355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
133625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Walk all the OpMemberDecorate for type's result id -- first pass, collect components.
13375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
13385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
13395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned member_index = insn.word(2);
13405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(3) == spv::DecorationComponent) {
13425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                unsigned component = insn.word(4);
13435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                member_components[member_index] = component;
13445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
13455b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes
13465b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes            if (insn.word(3) == spv::DecorationRelaxedPrecision) {
13475b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes                member_relaxed_precision[member_index] = 1;
13485b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes            }
13495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
13505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
13515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
135225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Second pass -- produce the output, from Location decorations
13535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
13545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
13555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned member_index = insn.word(2);
13565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned member_type_id = type.word(2 + member_index);
13575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(3) == spv::DecorationLocation) {
13595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                unsigned location = insn.word(4);
13605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                unsigned num_locations = get_locations_consumed_by_type(src, member_type_id, false);
13615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                auto component_it = member_components.find(member_index);
13625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                unsigned component = component_it == member_components.end() ? 0 : component_it->second;
13635b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes                bool is_relaxed_precision = member_relaxed_precision.find(member_index) != member_relaxed_precision.end();
13645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                for (unsigned int offset = 0; offset < num_locations; offset++) {
1366b0436668e6594b8528e96de7bed208399fb2431dChris Forbes                    interface_var v = {};
13675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.id = id;
136825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski                    // TODO: member index in interface_var too?
13695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.type_id = member_type_id;
13705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.offset = offset;
1371b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes                    v.is_patch = is_patch;
1372fff9393206f66a154438e16fa0562c989f425498Chris Forbes                    v.is_block_member = true;
13735b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes                    v.is_relaxed_precision = is_relaxed_precision;
13743a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes                    (*out)[std::make_pair(location + offset, component)] = v;
13755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
13765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
13775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
13785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
13795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
13805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1381bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic std::map<location_t, interface_var> collect_interface_by_location(shader_module const *src, spirv_inst_iter entrypoint,
1382bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                         spv::StorageClass sinterface, bool is_array_of_verts) {
13835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> var_locations;
13845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> var_builtins;
13855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> var_components;
13865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> blocks;
1387b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes    std::unordered_map<unsigned, unsigned> var_patch;
1388b0436668e6594b8528e96de7bed208399fb2431dChris Forbes    std::unordered_map<unsigned, unsigned> var_relaxed_precision;
13895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
139125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // We consider two interface models: SSO rendezvous-by-location, and builtins. Complain about anything that
139225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // fits neither model.
13935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpDecorate) {
13945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationLocation) {
13955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                var_locations[insn.word(1)] = insn.word(3);
13965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
13975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationBuiltIn) {
13995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                var_builtins[insn.word(1)] = insn.word(3);
14005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
14015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationComponent) {
14035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                var_components[insn.word(1)] = insn.word(3);
14045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
14055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationBlock) {
14075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                blocks[insn.word(1)] = 1;
14085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
1409b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes
1410b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes            if (insn.word(2) == spv::DecorationPatch) {
1411b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes                var_patch[insn.word(1)] = 1;
1412b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes            }
1413b0436668e6594b8528e96de7bed208399fb2431dChris Forbes
1414b0436668e6594b8528e96de7bed208399fb2431dChris Forbes            if (insn.word(2) == spv::DecorationRelaxedPrecision) {
1415b0436668e6594b8528e96de7bed208399fb2431dChris Forbes                var_relaxed_precision[insn.word(1)] = 1;
1416b0436668e6594b8528e96de7bed208399fb2431dChris Forbes            }
14175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
14185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
14195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
142025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // TODO: handle grouped decorations
142125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // TODO: handle index=1 dual source outputs from FS -- two vars will have the same location, and we DON'T want to clobber.
14225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
142325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Find the end of the entrypoint's name string. additional zero bytes follow the actual null terminator, to fill out the
142425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // rest of the word - so we only need to look at the last byte in the word to determine which word contains the terminator.
1425c15b801a6e1a5dd5eed09e689aecdde7c4a90a5bMichael Mc Donnell    uint32_t word = 3;
14265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while (entrypoint.word(word) & 0xff000000u) {
14275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        ++word;
14285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
14295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    ++word;
14305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14313a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    std::map<location_t, interface_var> out;
14323a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
14335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (; word < entrypoint.len(); word++) {
14345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto insn = src->get_def(entrypoint.word(word));
14355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        assert(insn != src->end());
14365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        assert(insn.opcode() == spv::OpVariable);
14375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14381d5109d5e0dcc530b27e632e73e1be5e12a28dcdJamie Madill        if (insn.word(3) == static_cast<uint32_t>(sinterface)) {
14395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned id = insn.word(2);
14405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned type = insn.word(1);
14415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            int location = value_or_default(var_locations, id, -1);
14435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            int builtin = value_or_default(var_builtins, id, -1);
1444cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            unsigned component = value_or_default(var_components, id, 0);  // Unspecified is OK, is 0
1445b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes            bool is_patch = var_patch.find(id) != var_patch.end();
1446b0436668e6594b8528e96de7bed208399fb2431dChris Forbes            bool is_relaxed_precision = var_relaxed_precision.find(id) != var_relaxed_precision.end();
14475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
144825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // All variables and interface block members in the Input or Output storage classes must be decorated with either
144925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // a builtin or an explicit location.
145025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            //
145125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // TODO: integrate the interface block support here. For now, don't complain -- a valid SPIRV module will only hit
145225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // this path for the interface block case, as the individual members of the type are decorated, rather than
145325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // variable declarations.
14545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (location != -1) {
145625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski                // A user-defined interface variable, with a location. Where a variable occupied multiple locations, emit
145725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski                // one result for each.
14587c755c8aca6857046df9516d8336416165969cb9Chris Forbes                unsigned num_locations = get_locations_consumed_by_type(src, type, is_array_of_verts && !is_patch);
14595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                for (unsigned int offset = 0; offset < num_locations; offset++) {
1460b0436668e6594b8528e96de7bed208399fb2431dChris Forbes                    interface_var v = {};
14615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.id = id;
14625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.type_id = type;
14635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.offset = offset;
1464b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes                    v.is_patch = is_patch;
1465b0436668e6594b8528e96de7bed208399fb2431dChris Forbes                    v.is_relaxed_precision = is_relaxed_precision;
14665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    out[std::make_pair(location + offset, component)] = v;
14675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
14685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else if (builtin == -1) {
146925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski                // An interface block instance
14703a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes                collect_interface_block_members(src, &out, blocks, is_array_of_verts, id, type, is_patch);
14715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
14725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
14735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
14743a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
14753a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    return out;
14765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
14775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1478cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskistatic std::vector<std::pair<uint32_t, interface_var>> collect_interface_by_input_attachment_index(
1479cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    debug_report_data *report_data, shader_module const *src, std::unordered_set<uint32_t> const &accessible_ids) {
14803a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    std::vector<std::pair<uint32_t, interface_var>> out;
1481745d49409296f060402b57950384caadb636a2b2Chris Forbes
1482745d49409296f060402b57950384caadb636a2b2Chris Forbes    for (auto insn : *src) {
1483745d49409296f060402b57950384caadb636a2b2Chris Forbes        if (insn.opcode() == spv::OpDecorate) {
1484745d49409296f060402b57950384caadb636a2b2Chris Forbes            if (insn.word(2) == spv::DecorationInputAttachmentIndex) {
1485745d49409296f060402b57950384caadb636a2b2Chris Forbes                auto attachment_index = insn.word(3);
1486745d49409296f060402b57950384caadb636a2b2Chris Forbes                auto id = insn.word(1);
1487745d49409296f060402b57950384caadb636a2b2Chris Forbes
1488745d49409296f060402b57950384caadb636a2b2Chris Forbes                if (accessible_ids.count(id)) {
1489745d49409296f060402b57950384caadb636a2b2Chris Forbes                    auto def = src->get_def(id);
1490745d49409296f060402b57950384caadb636a2b2Chris Forbes                    assert(def != src->end());
1491745d49409296f060402b57950384caadb636a2b2Chris Forbes
1492745d49409296f060402b57950384caadb636a2b2Chris Forbes                    if (def.opcode() == spv::OpVariable && insn.word(3) == spv::StorageClassUniformConstant) {
1493e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                        auto num_locations = get_locations_consumed_by_type(src, def.word(1), false);
1494e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                        for (unsigned int offset = 0; offset < num_locations; offset++) {
1495b0436668e6594b8528e96de7bed208399fb2431dChris Forbes                            interface_var v = {};
1496e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                            v.id = id;
1497e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                            v.type_id = def.word(1);
1498e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                            v.offset = offset;
1499e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                            out.emplace_back(attachment_index + offset, v);
1500e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                        }
1501745d49409296f060402b57950384caadb636a2b2Chris Forbes                    }
1502745d49409296f060402b57950384caadb636a2b2Chris Forbes                }
1503745d49409296f060402b57950384caadb636a2b2Chris Forbes            }
1504745d49409296f060402b57950384caadb636a2b2Chris Forbes        }
1505745d49409296f060402b57950384caadb636a2b2Chris Forbes    }
15063a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
15073a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    return out;
1508745d49409296f060402b57950384caadb636a2b2Chris Forbes}
1509745d49409296f060402b57950384caadb636a2b2Chris Forbes
1510cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskistatic std::vector<std::pair<descriptor_slot_t, interface_var>> collect_interface_by_descriptor_slot(
1511cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    debug_report_data *report_data, shader_module const *src, std::unordered_set<uint32_t> const &accessible_ids) {
15125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> var_sets;
15135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> var_bindings;
15145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
151625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // All variables in the Uniform or UniformConstant storage classes are required to be decorated with both
151725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // DecorationDescriptorSet and DecorationBinding.
15185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpDecorate) {
15195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationDescriptorSet) {
15205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                var_sets[insn.word(1)] = insn.word(3);
15215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
15225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationBinding) {
15245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                var_bindings[insn.word(1)] = insn.word(3);
15255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
15265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
15275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
15285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15293a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    std::vector<std::pair<descriptor_slot_t, interface_var>> out;
15303a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
15315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto id : accessible_ids) {
15325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto insn = src->get_def(id);
15335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        assert(insn != src->end());
15345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpVariable &&
15365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            (insn.word(3) == spv::StorageClassUniform || insn.word(3) == spv::StorageClassUniformConstant)) {
15375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned set = value_or_default(var_sets, insn.word(2), 0);
15385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned binding = value_or_default(var_bindings, insn.word(2), 0);
15395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1540b0436668e6594b8528e96de7bed208399fb2431dChris Forbes            interface_var v = {};
15415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            v.id = insn.word(2);
15425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            v.type_id = insn.word(1);
1543cefd4dd8e03c5dae11a05d04a03cb856190358e0Chris Forbes            out.emplace_back(std::make_pair(set, binding), v);
15445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
15455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
15463a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
15473a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    return out;
15485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
15495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1550edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_interface_between_stages(debug_report_data *report_data, shader_module const *producer,
1551031261d21af8907953dd763398ce9a23e65b8749Chris Forbes                                              spirv_inst_iter producer_entrypoint, shader_stage_attributes const *producer_stage,
15525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                              shader_module const *consumer, spirv_inst_iter consumer_entrypoint,
1553031261d21af8907953dd763398ce9a23e65b8749Chris Forbes                                              shader_stage_attributes const *consumer_stage) {
15545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool pass = true;
15555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1556bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto outputs =
1557bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        collect_interface_by_location(producer, producer_entrypoint, spv::StorageClassOutput, producer_stage->arrayed_output);
1558bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto inputs =
1559bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        collect_interface_by_location(consumer, consumer_entrypoint, spv::StorageClassInput, consumer_stage->arrayed_input);
15605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto a_it = outputs.begin();
15625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto b_it = inputs.begin();
15635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
156425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Maps sorted by key (location); walk them together to find mismatches
15655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while ((outputs.size() > 0 && a_it != outputs.end()) || (inputs.size() && b_it != inputs.end())) {
15665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        bool a_at_end = outputs.size() == 0 || a_it == outputs.end();
15675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        bool b_at_end = inputs.size() == 0 || b_it == inputs.end();
15685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto a_first = a_at_end ? std::make_pair(0u, 0u) : a_it->first;
15695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto b_first = b_at_end ? std::make_pair(0u, 0u) : b_it->first;
15705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (b_at_end || ((!a_at_end) && (a_first < b_first))) {
1572bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
1573bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC", "%s writes to output location %u.%u which is not consumed by %s",
1574bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        producer_stage->name, a_first.first, a_first.second, consumer_stage->name)) {
15755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pass = false;
15765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
15775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            a_it++;
15785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (a_at_end || a_first > b_first) {
1579bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
1580bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "%s consumes input location %u.%u which is not written by %s",
1581bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        consumer_stage->name, b_first.first, b_first.second, producer_stage->name)) {
15825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pass = false;
15835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
15845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            b_it++;
15855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
1586fff9393206f66a154438e16fa0562c989f425498Chris Forbes            // subtleties of arrayed interfaces:
1587fff9393206f66a154438e16fa0562c989f425498Chris Forbes            // - if is_patch, then the member is not arrayed, even though the interface may be.
1588fff9393206f66a154438e16fa0562c989f425498Chris Forbes            // - if is_block_member, then the extra array level of an arrayed interface is not
1589fff9393206f66a154438e16fa0562c989f425498Chris Forbes            //   expressed in the member type -- it's expressed in the block type.
15900f44c68c2575ba2fc83d8c8f2f5ea09548f40686Chris Forbes            if (!types_match(producer, consumer, a_it->second.type_id, b_it->second.type_id,
1591fff9393206f66a154438e16fa0562c989f425498Chris Forbes                             producer_stage->arrayed_output && !a_it->second.is_patch && !a_it->second.is_block_member,
1592bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             consumer_stage->arrayed_input && !b_it->second.is_patch && !b_it->second.is_block_member, true)) {
1593bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
1594bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC", "Type mismatch on location %u.%u: '%s' vs '%s'",
1595bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            a_first.first, a_first.second, describe_type(producer, a_it->second.type_id).c_str(),
15969ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes                            describe_type(consumer, b_it->second.type_id).c_str())) {
15975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    pass = false;
15985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
15995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
16000f44c68c2575ba2fc83d8c8f2f5ea09548f40686Chris Forbes            if (a_it->second.is_patch != b_it->second.is_patch) {
1601bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
1602bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
1603f706c50be3a9d4d1e131c2f43ee2fb443f028d30Chris Forbes                            "Decoration mismatch on location %u.%u: is per-%s in %s stage but "
1604bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "per-%s in %s stage",
1605bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            a_first.first, a_first.second, a_it->second.is_patch ? "patch" : "vertex", producer_stage->name,
16060f44c68c2575ba2fc83d8c8f2f5ea09548f40686Chris Forbes                            b_it->second.is_patch ? "patch" : "vertex", consumer_stage->name)) {
16070f44c68c2575ba2fc83d8c8f2f5ea09548f40686Chris Forbes                    pass = false;
16080f44c68c2575ba2fc83d8c8f2f5ea09548f40686Chris Forbes                }
16090f44c68c2575ba2fc83d8c8f2f5ea09548f40686Chris Forbes            }
161017c6bacf91ac671cb33212071b87b8ea782812f5Chris Forbes            if (a_it->second.is_relaxed_precision != b_it->second.is_relaxed_precision) {
1611bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
1612bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
1613bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "Decoration mismatch on location %u.%u: %s and %s stages differ in precision", a_first.first,
1614bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            a_first.second, producer_stage->name, consumer_stage->name)) {
161517c6bacf91ac671cb33212071b87b8ea782812f5Chris Forbes                    pass = false;
161617c6bacf91ac671cb33212071b87b8ea782812f5Chris Forbes                }
161717c6bacf91ac671cb33212071b87b8ea782812f5Chris Forbes            }
16185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            a_it++;
16195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            b_it++;
16205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
16215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
16225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
16235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return pass;
16245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
16255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
16265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisenum FORMAT_TYPE {
16275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    FORMAT_TYPE_UNDEFINED,
1628cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    FORMAT_TYPE_FLOAT,  // UNORM, SNORM, FLOAT, USCALED, SSCALED, SRGB -- anything we consider float in the shader
16295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    FORMAT_TYPE_SINT,
16305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    FORMAT_TYPE_UINT,
16315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis};
16325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
16335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic unsigned get_format_type(VkFormat fmt) {
16345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (fmt) {
1635cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_UNDEFINED:
1636cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return FORMAT_TYPE_UNDEFINED;
1637cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R8_SINT:
1638cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R8G8_SINT:
1639cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R8G8B8_SINT:
1640cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R8G8B8A8_SINT:
1641cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R16_SINT:
1642cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R16G16_SINT:
1643cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R16G16B16_SINT:
1644cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R16G16B16A16_SINT:
1645cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R32_SINT:
1646cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R32G32_SINT:
1647cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R32G32B32_SINT:
1648cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R32G32B32A32_SINT:
1649cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64_SINT:
1650cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64_SINT:
1651cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64_SINT:
1652cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64A64_SINT:
1653cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_B8G8R8_SINT:
1654cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_B8G8R8A8_SINT:
1655cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_A8B8G8R8_SINT_PACK32:
1656cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_A2B10G10R10_SINT_PACK32:
1657cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_A2R10G10B10_SINT_PACK32:
1658cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return FORMAT_TYPE_SINT;
1659cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R8_UINT:
1660cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R8G8_UINT:
1661cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R8G8B8_UINT:
1662cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R8G8B8A8_UINT:
1663cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R16_UINT:
1664cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R16G16_UINT:
1665cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R16G16B16_UINT:
1666cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R16G16B16A16_UINT:
1667cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R32_UINT:
1668cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R32G32_UINT:
1669cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R32G32B32_UINT:
1670cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R32G32B32A32_UINT:
1671cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64_UINT:
1672cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64_UINT:
1673cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64_UINT:
1674cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64A64_UINT:
1675cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_B8G8R8_UINT:
1676cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_B8G8R8A8_UINT:
1677cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_A8B8G8R8_UINT_PACK32:
1678cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_A2B10G10R10_UINT_PACK32:
1679cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_A2R10G10B10_UINT_PACK32:
1680cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return FORMAT_TYPE_UINT;
1681cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1682cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return FORMAT_TYPE_FLOAT;
16835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
16845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
16855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
168625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// characterizes a SPIR-V type appearing in an interface to a FF stage, for comparison to a VkFormat's characterization above.
16875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic unsigned get_fundamental_type(shader_module const *src, unsigned type) {
16885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto insn = src->get_def(type);
16895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(insn != src->end());
16905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
16915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (insn.opcode()) {
1692cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeInt:
1693cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return insn.word(3) ? FORMAT_TYPE_SINT : FORMAT_TYPE_UINT;
1694cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeFloat:
1695cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return FORMAT_TYPE_FLOAT;
1696cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeVector:
1697cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_fundamental_type(src, insn.word(2));
1698cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeMatrix:
1699cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_fundamental_type(src, insn.word(2));
1700cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeArray:
1701cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_fundamental_type(src, insn.word(2));
1702cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypePointer:
1703cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_fundamental_type(src, insn.word(3));
1704cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeImage:
1705cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_fundamental_type(src, insn.word(2));
1706cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski
1707cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1708cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return FORMAT_TYPE_UNDEFINED;
17095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
17105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
17115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic uint32_t get_shader_stage_id(VkShaderStageFlagBits stage) {
17135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t bit_pos = u_ffs(stage);
17145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return bit_pos - 1;
17155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
17165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1717edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_vi_consistency(debug_report_data *report_data, VkPipelineVertexInputStateCreateInfo const *vi) {
171825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Walk the binding descriptions, which describe the step rate and stride of each vertex buffer.  Each binding should
171925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // be specified only once.
17205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<uint32_t, VkVertexInputBindingDescription const *> bindings;
17215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool pass = true;
17225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (unsigned i = 0; i < vi->vertexBindingDescriptionCount; i++) {
17245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto desc = &vi->pVertexBindingDescriptions[i];
17255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto &binding = bindings[desc->binding];
17265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (binding) {
17274f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes            // TODO: VALIDATION_ERROR_02105 perhaps?
1728bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
1729bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        SHADER_CHECKER_INCONSISTENT_VI, "SC", "Duplicate vertex input binding descriptions for binding %d",
1730bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        desc->binding)) {
17315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pass = false;
17325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
17335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
17345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            binding = desc;
17355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
17365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
17375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return pass;
17395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
17405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1741edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_vi_against_vs_inputs(debug_report_data *report_data, VkPipelineVertexInputStateCreateInfo const *vi,
17425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                          shader_module const *vs, spirv_inst_iter entrypoint) {
17435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool pass = true;
17445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17453a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    auto inputs = collect_interface_by_location(vs, entrypoint, spv::StorageClassInput, false);
17465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
174725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Build index by location
17485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::map<uint32_t, VkVertexInputAttributeDescription const *> attribs;
17495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (vi) {
1750c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes        for (unsigned i = 0; i < vi->vertexAttributeDescriptionCount; i++) {
1751c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes            auto num_locations = get_locations_consumed_by_format(vi->pVertexAttributeDescriptions[i].format);
1752c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes            for (auto j = 0u; j < num_locations; j++) {
1753c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes                attribs[vi->pVertexAttributeDescriptions[i].location + j] = &vi->pVertexAttributeDescriptions[i];
1754c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes            }
1755c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes        }
17565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
17575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto it_a = attribs.begin();
17595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto it_b = inputs.begin();
17601730e0dd28b3abc660b4e4704cf6d414f7fd4ad6Chris Forbes    bool used = false;
17615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while ((attribs.size() > 0 && it_a != attribs.end()) || (inputs.size() > 0 && it_b != inputs.end())) {
17635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        bool a_at_end = attribs.size() == 0 || it_a == attribs.end();
17645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        bool b_at_end = inputs.size() == 0 || it_b == inputs.end();
17655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto a_first = a_at_end ? 0 : it_a->first;
17665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto b_first = b_at_end ? 0 : it_b->first.first;
17675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!a_at_end && (b_at_end || a_first < b_first)) {
17681730e0dd28b3abc660b4e4704cf6d414f7fd4ad6Chris Forbes            if (!used && log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
1769bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 __LINE__, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",
1770bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 "Vertex attribute at location %d not consumed by vertex shader", a_first)) {
17715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pass = false;
17725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
17731730e0dd28b3abc660b4e4704cf6d414f7fd4ad6Chris Forbes            used = false;
17745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            it_a++;
17755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (!b_at_end && (a_at_end || b_first < a_first)) {
1776bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
1777bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "Vertex shader consumes input at location %d but not provided",
17785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        b_first)) {
17795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pass = false;
17805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
17815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            it_b++;
17825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
17835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned attrib_type = get_format_type(it_a->second->format);
17845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned input_type = get_fundamental_type(vs, it_b->second.type_id);
17855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
178625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // Type checking
17875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (attrib_type != FORMAT_TYPE_UNDEFINED && input_type != FORMAT_TYPE_UNDEFINED && attrib_type != input_type) {
1788bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
1789bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
17904b5890faffa54a735782a6b0a628a991ddc86944Mike Weiblen                            "Attribute type of `%s` at location %d does not match vertex shader input type of `%s`",
1791bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            string_VkFormat(it_a->second->format), a_first, describe_type(vs, it_b->second.type_id).c_str())) {
17925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    pass = false;
17935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
17945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
17955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
179625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // OK!
17971730e0dd28b3abc660b4e4704cf6d414f7fd4ad6Chris Forbes            used = true;
17985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            it_b++;
17995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
18005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
18015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return pass;
18035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
18045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1805edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_fs_outputs_against_render_pass(debug_report_data *report_data, shader_module const *fs,
18068da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis                                                    spirv_inst_iter entrypoint, VkRenderPassCreateInfo const *rpci,
18078da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis                                                    uint32_t subpass_index) {
1808025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes    std::map<uint32_t, VkFormat> color_attachments;
18098da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis    auto subpass = rpci->pSubpasses[subpass_index];
18108da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis    for (auto i = 0u; i < subpass.colorAttachmentCount; ++i) {
1811d9da90d92748c37962766868f8b0354637672c2aTobin Ehlis        uint32_t attachment = subpass.pColorAttachments[i].attachment;
1812cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (attachment == VK_ATTACHMENT_UNUSED) continue;
1813d9da90d92748c37962766868f8b0354637672c2aTobin Ehlis        if (rpci->pAttachments[attachment].format != VK_FORMAT_UNDEFINED) {
1814d9da90d92748c37962766868f8b0354637672c2aTobin Ehlis            color_attachments[i] = rpci->pAttachments[attachment].format;
1815025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes        }
1816025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes    }
1817025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes
18185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool pass = true;
18195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
182025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // TODO: dual source blend index (spv::DecIndex, zero if not provided)
18215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18223a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    auto outputs = collect_interface_by_location(fs, entrypoint, spv::StorageClassOutput, false);
18235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1824025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes    auto it_a = outputs.begin();
1825025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes    auto it_b = color_attachments.begin();
18265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
182725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Walk attachment list and outputs together
1828025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes
1829025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes    while ((outputs.size() > 0 && it_a != outputs.end()) || (color_attachments.size() > 0 && it_b != color_attachments.end())) {
1830025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes        bool a_at_end = outputs.size() == 0 || it_a == outputs.end();
1831025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes        bool b_at_end = color_attachments.size() == 0 || it_b == color_attachments.end();
18325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1833025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes        if (!a_at_end && (b_at_end || it_a->first.first < it_b->first)) {
1834bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
1835bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",
1836d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen                        "fragment shader writes to output location %d with no matching attachment", it_a->first.first)) {
18375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pass = false;
18385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
1839025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            it_a++;
1840025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes        } else if (!b_at_end && (a_at_end || it_a->first.first > it_b->first)) {
1841bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
1842bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "Attachment %d not written by fragment shader", it_b->first)) {
18435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pass = false;
18445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
1845025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            it_b++;
18465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
1847025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            unsigned output_type = get_fundamental_type(fs, it_a->second.type_id);
1848025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            unsigned att_type = get_format_type(it_b->second);
18495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
185025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // Type checking
18515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (att_type != FORMAT_TYPE_UNDEFINED && output_type != FORMAT_TYPE_UNDEFINED && att_type != output_type) {
1852bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
1853bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
1854d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen                            "Attachment %d of type `%s` does not match fragment shader output type of `%s`", it_b->first,
1855bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            string_VkFormat(it_b->second), describe_type(fs, it_a->second.type_id).c_str())) {
18565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    pass = false;
18575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
18585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
18595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
186025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // OK!
1861025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            it_a++;
1862025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            it_b++;
18635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
18645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
18655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return pass;
18675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
18685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
186925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// For some analyses, we need to know about all ids referenced by the static call tree of a particular entrypoint. This is
187025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// important for identifying the set of shader resources actually used by an entrypoint, for example.
187125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// Note: we only explore parts of the image which might actually contain ids we care about for the above analyses.
187225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski//  - NOT the shader input/output interfaces.
187325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski//
187425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// TODO: The set of interesting opcodes here was determined by eyeballing the SPIRV spec. It might be worth
187525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// converting parts of this to be generated from the machine-readable spec instead.
18763a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbesstatic std::unordered_set<uint32_t> mark_accessible_ids(shader_module const *src, spirv_inst_iter entrypoint) {
18773a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    std::unordered_set<uint32_t> ids;
18785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_set<uint32_t> worklist;
18795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    worklist.insert(entrypoint.word(2));
18805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while (!worklist.empty()) {
18825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto id_iter = worklist.begin();
18835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto id = *id_iter;
18845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        worklist.erase(id_iter);
18855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto insn = src->get_def(id);
18875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn == src->end()) {
188825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // ID is something we didn't collect in build_def_index. that's OK -- we'll stumble across all kinds of things here
188925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // that we may not care about.
18905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            continue;
18915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
18925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
189325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Try to add to the output set
18945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!ids.insert(id).second) {
1895cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            continue;  // If we already saw this id, we don't want to walk it again.
18965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
18975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        switch (insn.opcode()) {
1899cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpFunction:
1900cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // Scan whole body of the function, enlisting anything interesting
1901cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                while (++insn, insn.opcode() != spv::OpFunctionEnd) {
1902cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    switch (insn.opcode()) {
1903cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpLoad:
1904cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicLoad:
1905cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicExchange:
1906cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicCompareExchange:
1907cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicCompareExchangeWeak:
1908cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicIIncrement:
1909cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicIDecrement:
1910cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicIAdd:
1911cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicISub:
1912cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicSMin:
1913cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicUMin:
1914cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicSMax:
1915cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicUMax:
1916cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicAnd:
1917cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicOr:
1918cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicXor:
1919cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            worklist.insert(insn.word(3));  // ptr
1920cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
1921cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpStore:
1922cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicStore:
1923cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            worklist.insert(insn.word(1));  // ptr
1924cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
1925cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAccessChain:
1926cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpInBoundsAccessChain:
1927cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            worklist.insert(insn.word(3));  // base ptr
1928cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
1929cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpSampledImage:
1930cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleImplicitLod:
1931cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleExplicitLod:
1932cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleDrefImplicitLod:
1933cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleDrefExplicitLod:
1934cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleProjImplicitLod:
1935cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleProjExplicitLod:
1936cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleProjDrefImplicitLod:
1937cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleProjDrefExplicitLod:
1938cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageFetch:
1939cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageGather:
1940cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageDrefGather:
1941cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageRead:
1942cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImage:
1943cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQueryFormat:
1944cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQueryOrder:
1945cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQuerySizeLod:
1946cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQuerySize:
1947cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQueryLod:
1948cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQueryLevels:
1949cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQuerySamples:
1950cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleImplicitLod:
1951cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleExplicitLod:
1952cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleDrefImplicitLod:
1953cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleDrefExplicitLod:
1954cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleProjImplicitLod:
1955cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleProjExplicitLod:
1956cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleProjDrefImplicitLod:
1957cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleProjDrefExplicitLod:
1958cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseFetch:
1959cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseGather:
1960cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseDrefGather:
1961cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageTexelPointer:
1962cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            worklist.insert(insn.word(3));  // Image or sampled image
1963cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
1964cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageWrite:
1965cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            worklist.insert(insn.word(1));  // Image -- different operand order to above
1966cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
1967cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpFunctionCall:
1968cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            for (uint32_t i = 3; i < insn.len(); i++) {
1969cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                worklist.insert(insn.word(i));  // fn itself, and all args
1970cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            }
1971cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
19725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1973cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpExtInst:
1974cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            for (uint32_t i = 5; i < insn.len(); i++) {
1975cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                worklist.insert(insn.word(i));  // Operands to ext inst
1976cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            }
1977cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
19785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
19795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
1980cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
19815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
19825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
19833a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
19843a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    return ids;
19855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
19865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1987edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_push_constant_block_against_pipeline(debug_report_data *report_data,
1988416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis                                                          std::vector<VkPushConstantRange> const *push_constant_ranges,
19895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                          shader_module const *src, spirv_inst_iter type,
19905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                          VkShaderStageFlagBits stage) {
19915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool pass = true;
19925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
199325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Strip off ptrs etc
19945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    type = get_struct_type(src, type, false);
19955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(type != src->end());
19965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
199725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Validate directly off the offsets. this isn't quite correct for arrays and matrices, but is a good first step.
199825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // TODO: arrays, matrices, weird sizes
19995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
20005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
20015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(3) == spv::DecorationOffset) {
20025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                unsigned offset = insn.word(4);
2003cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto size = 4;  // Bytes; TODO: calculate this based on the type
20045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                bool found_range = false;
2006416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis                for (auto const &range : *push_constant_ranges) {
20075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    if (range.offset <= offset && range.offset + range.size >= offset + size) {
20085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        found_range = true;
20095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        if ((range.stageFlags & stage) == 0) {
2011bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
2012bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        SHADER_CHECKER_PUSH_CONSTANT_NOT_ACCESSIBLE_FROM_STAGE, "SC",
20135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                        "Push constant range covering variable starting at "
20145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                        "offset %u not accessible from stage %s",
20155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                        offset, string_VkShaderStageFlagBits(stage))) {
20165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                pass = false;
20175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                            }
20185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        }
20195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        break;
20215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
20225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
20235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (!found_range) {
2025bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
2026bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                SHADER_CHECKER_PUSH_CONSTANT_OUT_OF_RANGE, "SC",
20275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                "Push constant range covering variable starting at "
20285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                "offset %u not declared in layout",
20295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                offset)) {
20305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        pass = false;
20315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
20325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
20335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
20345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
20355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
20365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return pass;
20385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
20395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2040edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_push_constant_usage(debug_report_data *report_data,
2041416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis                                         std::vector<VkPushConstantRange> const *push_constant_ranges, shader_module const *src,
20425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                         std::unordered_set<uint32_t> accessible_ids, VkShaderStageFlagBits stage) {
20435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool pass = true;
20445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto id : accessible_ids) {
20465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto def_insn = src->get_def(id);
20475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (def_insn.opcode() == spv::OpVariable && def_insn.word(3) == spv::StorageClassPushConstant) {
2048416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis            pass &= validate_push_constant_block_against_pipeline(report_data, push_constant_ranges, src,
2049416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis                                                                  src->get_def(def_insn.word(1)), stage);
20505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
20515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
20525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return pass;
20545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
20555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2056fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis// For given pipelineLayout verify that the set_layout_node at slot.first
2057fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis//  has the requested binding at slot.second and return ptr to that binding
2058bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic VkDescriptorSetLayoutBinding const *get_descriptor_binding(PIPELINE_LAYOUT_NODE const *pipelineLayout,
2059bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                  descriptor_slot_t slot) {
2060cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!pipelineLayout) return nullptr;
20615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2062cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (slot.first >= pipelineLayout->set_layouts.size()) return nullptr;
20635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2064416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis    return pipelineLayout->set_layouts[slot.first]->GetDescriptorSetLayoutBindingPtrFromBinding(slot.second);
20655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
20665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Block of code at start here for managing/tracking Pipeline state that this layer cares about
20685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// TODO : Should be tracking lastBound per commandBuffer and when draws occur, report based on that cmd buffer lastBound
20705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//   Then need to synchronize the accesses based on cmd buffer so that if I'm reading state on one cmd buffer, updates
20715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//   to that same cmd buffer by separate thread are not changing state from underneath us
20725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Track the last cmd buffer touched by this thread
20735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2074e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool hasDrawCmd(GLOBAL_CB_NODE *pCB) {
20755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < NUM_DRAW_TYPES; i++) {
2076cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (pCB->drawCount[i]) return true;
20775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2078e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    return false;
20795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
20805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Check object status for selected flag state
2082e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool validate_status(layer_data *my_data, GLOBAL_CB_NODE *pNode, CBStatusFlags status_mask, VkFlags msg_flags,
20834f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                            const char *fail_msg, UNIQUE_VALIDATION_ERROR_CODE const msg_code) {
20843d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    if (!(pNode->status & status_mask)) {
20854f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes        char const *const message = validation_error_map[msg_code];
20863d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        return log_msg(my_data->report_data, msg_flags, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
20874f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                       reinterpret_cast<const uint64_t &>(pNode->commandBuffer), __LINE__, msg_code, "DS",
20884f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                       "command buffer object 0x%p: %s. %s.", pNode->commandBuffer, fail_msg, message);
20895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2090e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    return false;
20915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
20925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Retrieve pipeline node ptr for given pipeline object
20944c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic PIPELINE_STATE *getPipelineState(layer_data const *my_data, VkPipeline pipeline) {
2095ea8349eeee76ae2859c10870fd8bd9e60309eb28Chris Forbes    auto it = my_data->pipelineMap.find(pipeline);
2096ea8349eeee76ae2859c10870fd8bd9e60309eb28Chris Forbes    if (it == my_data->pipelineMap.end()) {
2097ea8349eeee76ae2859c10870fd8bd9e60309eb28Chris Forbes        return nullptr;
20985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2099ea8349eeee76ae2859c10870fd8bd9e60309eb28Chris Forbes    return it->second;
21005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
21015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2102127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlisstatic RENDER_PASS_STATE *getRenderPassState(layer_data const *my_data, VkRenderPass renderpass) {
210316387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes    auto it = my_data->renderPassMap.find(renderpass);
210416387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes    if (it == my_data->renderPassMap.end()) {
210516387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes        return nullptr;
210616387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes    }
2107fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    return it->second.get();
210816387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes}
210916387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes
2110c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlisstatic FRAMEBUFFER_STATE *getFramebufferState(const layer_data *my_data, VkFramebuffer framebuffer) {
2111f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes    auto it = my_data->frameBufferMap.find(framebuffer);
2112f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes    if (it == my_data->frameBufferMap.end()) {
2113f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes        return nullptr;
2114f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes    }
211504861caca7eb93a5241b164e8480bb93c826902cTobin Ehlis    return it->second.get();
2116f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes}
2117f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes
2118e3f7c45fd64a44a67ce96c89e2bbee426c6ecf24Tobin Ehliscvdescriptorset::DescriptorSetLayout const *getDescriptorSetLayout(layer_data const *my_data, VkDescriptorSetLayout dsLayout) {
211911f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes    auto it = my_data->descriptorSetLayoutMap.find(dsLayout);
212011f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes    if (it == my_data->descriptorSetLayoutMap.end()) {
212111f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes        return nullptr;
212211f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes    }
212311f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes    return it->second;
212411f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes}
212511f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes
2126c2a5a36d03bbe52f5854a5884346e4a84115e259Tobin Ehlisstatic PIPELINE_LAYOUT_NODE const *getPipelineLayout(layer_data const *my_data, VkPipelineLayout pipeLayout) {
21274a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes    auto it = my_data->pipelineLayoutMap.find(pipeLayout);
21284a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes    if (it == my_data->pipelineLayoutMap.end()) {
21294a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes        return nullptr;
21304a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes    }
21314a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes    return &it->second;
21324a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes}
21334a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes
2134e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves// Return true if for a given PSO, the given state enum is dynamic, else return false
21354c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic bool isDynamic(const PIPELINE_STATE *pPipeline, const VkDynamicState state) {
21365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pPipeline && pPipeline->graphicsPipelineCI.pDynamicState) {
21375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < pPipeline->graphicsPipelineCI.pDynamicState->dynamicStateCount; i++) {
2138cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (state == pPipeline->graphicsPipelineCI.pDynamicState->pDynamicStates[i]) return true;
21395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
21405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2141e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    return false;
21425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
21435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
21445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Validate state stored as flags at time of draw call
21454f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayesstatic bool validate_draw_state_flags(layer_data *dev_data, GLOBAL_CB_NODE *pCB, const PIPELINE_STATE *pPipe, bool indexed,
21464f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                      UNIQUE_VALIDATION_ERROR_CODE const msg_code) {
21479c4006684a13db43f0dbc8d0015a9ef34872ca09Chris Forbes    bool result = false;
2148ca546210846c65808717f8875deae39bd227c240Tobin Ehlis    if (pPipe->graphicsPipelineCI.pInputAssemblyState &&
2149ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        ((pPipe->graphicsPipelineCI.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST) ||
2150ca546210846c65808717f8875deae39bd227c240Tobin Ehlis         (pPipe->graphicsPipelineCI.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP))) {
21513d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_LINE_WIDTH_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
21524f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic line width state not set for this command buffer", msg_code);
21533d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
215445824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves    if (pPipe->graphicsPipelineCI.pRasterizationState &&
215545824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves        (pPipe->graphicsPipelineCI.pRasterizationState->depthBiasEnable == VK_TRUE)) {
21563d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_DEPTH_BIAS_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
21574f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic depth bias state not set for this command buffer", msg_code);
21583d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
21593d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    if (pPipe->blendConstantsEnabled) {
21603d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_BLEND_CONSTANTS_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
21614f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic blend constants state not set for this command buffer", msg_code);
21623d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
216345824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves    if (pPipe->graphicsPipelineCI.pDepthStencilState &&
216445824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves        (pPipe->graphicsPipelineCI.pDepthStencilState->depthBoundsTestEnable == VK_TRUE)) {
21653d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_DEPTH_BOUNDS_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
21664f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic depth bounds state not set for this command buffer", msg_code);
21673d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
216845824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves    if (pPipe->graphicsPipelineCI.pDepthStencilState &&
216945824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves        (pPipe->graphicsPipelineCI.pDepthStencilState->stencilTestEnable == VK_TRUE)) {
21703d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_STENCIL_READ_MASK_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
21714f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic stencil read mask state not set for this command buffer", msg_code);
21723d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_STENCIL_WRITE_MASK_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
21734f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic stencil write mask state not set for this command buffer", msg_code);
21743d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_STENCIL_REFERENCE_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
21754f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic stencil reference state not set for this command buffer", msg_code);
21763d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
21771c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    if (indexed) {
21783d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_INDEX_BUFFER_BOUND, VK_DEBUG_REPORT_ERROR_BIT_EXT,
21794f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Index buffer object not bound to this command buffer when Indexed Draw attempted", msg_code);
21803d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
21814f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes
21825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
21835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
21845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
21855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Verify attachment reference compatibility according to spec
21865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  If one array is larger, treat missing elements of shorter array as VK_ATTACHMENT_UNUSED & other array much match this
21875ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski//  If both AttachmentReference arrays have requested index, check their corresponding AttachmentDescriptions
21885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//   to make sure that format and samples counts match.
21895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  If not, they are not compatible.
21905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic bool attachment_references_compatible(const uint32_t index, const VkAttachmentReference *pPrimary,
21915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                             const uint32_t primaryCount, const VkAttachmentDescription *pPrimaryAttachments,
21925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                             const VkAttachmentReference *pSecondary, const uint32_t secondaryCount,
21935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                             const VkAttachmentDescription *pSecondaryAttachments) {
2194e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis    // Check potential NULL cases first to avoid nullptr issues later
2195e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis    if (pPrimary == nullptr) {
2196e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis        if (pSecondary == nullptr) {
2197e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis            return true;
2198e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis        }
2199e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis        return false;
2200e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis    } else if (pSecondary == nullptr) {
2201e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis        return false;
2202e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis    }
2203cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (index >= primaryCount) {  // Check secondary as if primary is VK_ATTACHMENT_UNUSED
2204cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (VK_ATTACHMENT_UNUSED == pSecondary[index].attachment) return true;
2205cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    } else if (index >= secondaryCount) {  // Check primary as if secondary is VK_ATTACHMENT_UNUSED
2206cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (VK_ATTACHMENT_UNUSED == pPrimary[index].attachment) return true;
2207cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    } else {  // Format and sample count must match
22085ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski        if ((pPrimary[index].attachment == VK_ATTACHMENT_UNUSED) && (pSecondary[index].attachment == VK_ATTACHMENT_UNUSED)) {
22095ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski            return true;
22105ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski        } else if ((pPrimary[index].attachment == VK_ATTACHMENT_UNUSED) || (pSecondary[index].attachment == VK_ATTACHMENT_UNUSED)) {
22115ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski            return false;
22125ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski        }
22135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if ((pPrimaryAttachments[pPrimary[index].attachment].format ==
22145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis             pSecondaryAttachments[pSecondary[index].attachment].format) &&
22155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            (pPrimaryAttachments[pPrimary[index].attachment].samples ==
22165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis             pSecondaryAttachments[pSecondary[index].attachment].samples))
22175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return true;
22185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
22195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Format and sample counts didn't match
22205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return false;
22215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
2222a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis// TODO : Scrub verify_renderpass_compatibility() and validateRenderPassCompatibility() and unify them and/or share code
22238da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis// For given primary RenderPass object and secondry RenderPassCreateInfo, verify that they're compatible
2224a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlisstatic bool verify_renderpass_compatibility(const layer_data *my_data, const VkRenderPassCreateInfo *primaryRPCI,
22258da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis                                            const VkRenderPassCreateInfo *secondaryRPCI, string &errorMsg) {
22265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (primaryRPCI->subpassCount != secondaryRPCI->subpassCount) {
2227c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes        stringstream errorStr;
22285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        errorStr << "RenderPass for primary cmdBuffer has " << primaryRPCI->subpassCount
22295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                 << " subpasses but renderPass for secondary cmdBuffer has " << secondaryRPCI->subpassCount << " subpasses.";
22305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        errorMsg = errorStr.str();
22315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return false;
22325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
22335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t spIndex = 0;
22345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (spIndex = 0; spIndex < primaryRPCI->subpassCount; ++spIndex) {
22355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // For each subpass, verify that corresponding color, input, resolve & depth/stencil attachment references are compatible
22365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primaryColorCount = primaryRPCI->pSubpasses[spIndex].colorAttachmentCount;
22375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t secondaryColorCount = secondaryRPCI->pSubpasses[spIndex].colorAttachmentCount;
22385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t colorMax = std::max(primaryColorCount, secondaryColorCount);
22395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t cIdx = 0; cIdx < colorMax; ++cIdx) {
22405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!attachment_references_compatible(cIdx, primaryRPCI->pSubpasses[spIndex].pColorAttachments, primaryColorCount,
22415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                  primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pColorAttachments,
22425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                  secondaryColorCount, secondaryRPCI->pAttachments)) {
2243c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes                stringstream errorStr;
22445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorStr << "color attachments at index " << cIdx << " of subpass index " << spIndex << " are not compatible.";
22455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorMsg = errorStr.str();
22465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return false;
22475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else if (!attachment_references_compatible(cIdx, primaryRPCI->pSubpasses[spIndex].pResolveAttachments,
22485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                         primaryColorCount, primaryRPCI->pAttachments,
22495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                         secondaryRPCI->pSubpasses[spIndex].pResolveAttachments,
22505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                         secondaryColorCount, secondaryRPCI->pAttachments)) {
2251c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes                stringstream errorStr;
22525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorStr << "resolve attachments at index " << cIdx << " of subpass index " << spIndex << " are not compatible.";
22535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorMsg = errorStr.str();
22545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return false;
22555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
22565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
2257fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes
2258bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        if (!attachment_references_compatible(0, primaryRPCI->pSubpasses[spIndex].pDepthStencilAttachment, 1,
2259bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pDepthStencilAttachment,
2260fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes                                              1, secondaryRPCI->pAttachments)) {
2261c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes            stringstream errorStr;
2262fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes            errorStr << "depth/stencil attachments of subpass index " << spIndex << " are not compatible.";
2263fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes            errorMsg = errorStr.str();
2264fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes            return false;
2265fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes        }
2266fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes
22675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primaryInputCount = primaryRPCI->pSubpasses[spIndex].inputAttachmentCount;
22685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t secondaryInputCount = secondaryRPCI->pSubpasses[spIndex].inputAttachmentCount;
22695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t inputMax = std::max(primaryInputCount, secondaryInputCount);
22705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < inputMax; ++i) {
22715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!attachment_references_compatible(i, primaryRPCI->pSubpasses[spIndex].pInputAttachments, primaryColorCount,
22725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                  primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pInputAttachments,
22735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                  secondaryColorCount, secondaryRPCI->pAttachments)) {
2274c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes                stringstream errorStr;
22755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorStr << "input attachments at index " << i << " of subpass index " << spIndex << " are not compatible.";
22765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorMsg = errorStr.str();
22775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return false;
22785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
22795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
22805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
22815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return true;
22825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
22835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2284397d27da37095073c8b86f9ff5289d0a39ce486eTobin Ehlis// For given cvdescriptorset::DescriptorSet, verify that its Set is compatible w/ the setLayout corresponding to
2285397d27da37095073c8b86f9ff5289d0a39ce486eTobin Ehlis// pipelineLayout[layoutIndex]
22861c130ea631a82716dc7334de17767536525f2292Tobin Ehlisstatic bool verify_set_layout_compatibility(layer_data *my_data, const cvdescriptorset::DescriptorSet *descriptor_set,
228769b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                                            PIPELINE_LAYOUT_NODE const *pipeline_layout, const uint32_t layoutIndex,
228869b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                                            string &errorMsg) {
2289416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis    auto num_sets = pipeline_layout->set_layouts.size();
22909b5d124aff50234cb0450e1b805baef577c90d83Tobin Ehlis    if (layoutIndex >= num_sets) {
2291c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes        stringstream errorStr;
229269b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis        errorStr << "VkPipelineLayout (" << pipeline_layout->layout << ") only contains " << num_sets
229369b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                 << " setLayouts corresponding to sets 0-" << num_sets - 1 << ", but you're attempting to bind set to index "
229469b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                 << layoutIndex;
22955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        errorMsg = errorStr.str();
22965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return false;
22975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2298416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis    auto layout_node = pipeline_layout->set_layouts[layoutIndex];
22991c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    return descriptor_set->IsCompatible(layout_node, &errorMsg);
23005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
23015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
23025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Validate that data for each specialization entry is fully contained within the buffer.
2303edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_specialization_offsets(debug_report_data *report_data, VkPipelineShaderStageCreateInfo const *info) {
2304e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool pass = true;
23055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
23065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkSpecializationInfo const *spec = info->pSpecializationInfo;
23075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
23085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (spec) {
23095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto i = 0u; i < spec->mapEntryCount; i++) {
23104f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes            // TODO: This is a good place for VALIDATION_ERROR_00589.
23115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (spec->pMapEntries[i].offset + spec->pMapEntries[i].size > spec->dataSize) {
23124f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
23134f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                            VALIDATION_ERROR_00590, "SC",
23145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                            "Specialization entry %u (for constant id %u) references memory outside provided "
23155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                            "specialization data (bytes %u.." PRINTF_SIZE_T_SPECIFIER "; " PRINTF_SIZE_T_SPECIFIER
23164f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                            " bytes provided). %s.",
23175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                            i, spec->pMapEntries[i].constantID, spec->pMapEntries[i].offset,
23184f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                            spec->pMapEntries[i].offset + spec->pMapEntries[i].size - 1, spec->dataSize,
23194f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                            validation_error_map[VALIDATION_ERROR_00590])) {
2320e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                    pass = false;
23215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
23225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
23235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
23245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
23255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
23265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return pass;
23275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
23285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2329bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool descriptor_type_match(shader_module const *module, uint32_t type_id, VkDescriptorType descriptor_type,
2330bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                  unsigned &descriptor_count) {
23315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto type = module->get_def(type_id);
23325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
23331b8c581791ac3c05d7829e04a2d8ecb964b8f2a6Chris Forbes    descriptor_count = 1;
23341b8c581791ac3c05d7829e04a2d8ecb964b8f2a6Chris Forbes
233525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Strip off any array or ptrs. Where we remove array levels, adjust the  descriptor count for each dimension.
23365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while (type.opcode() == spv::OpTypeArray || type.opcode() == spv::OpTypePointer) {
23377b892d2fc502b57d26dc9bff61b0f23cccc595fdChris Forbes        if (type.opcode() == spv::OpTypeArray) {
23387b892d2fc502b57d26dc9bff61b0f23cccc595fdChris Forbes            descriptor_count *= get_constant_value(module, type.word(3));
23397b892d2fc502b57d26dc9bff61b0f23cccc595fdChris Forbes            type = module->get_def(type.word(2));
2340bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        } else {
23417b892d2fc502b57d26dc9bff61b0f23cccc595fdChris Forbes            type = module->get_def(type.word(3));
23427b892d2fc502b57d26dc9bff61b0f23cccc595fdChris Forbes        }
23435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
23445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
23455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (type.opcode()) {
2346cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeStruct: {
2347cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            for (auto insn : *module) {
2348cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (insn.opcode() == spv::OpDecorate && insn.word(1) == type.word(1)) {
2349cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    if (insn.word(2) == spv::DecorationBlock) {
2350cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ||
2351cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                               descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
2352cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    } else if (insn.word(2) == spv::DecorationBufferBlock) {
2353cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ||
2354cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                               descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
2355cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    }
23565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
23575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
23585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2359cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Invalid
2360cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return false;
2361cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
23625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2363cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeSampler:
2364cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return descriptor_type == VK_DESCRIPTOR_TYPE_SAMPLER || descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
23655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2366cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeSampledImage:
2367cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) {
2368cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // Slight relaxation for some GLSL historical madness: samplerBuffer doesn't really have a sampler, and a texel
2369cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // buffer descriptor doesn't really provide one. Allow this slight mismatch.
2370cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto image_type = module->get_def(type.word(2));
2371cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto dim = image_type.word(3);
2372cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto sampled = image_type.word(7);
2373cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return dim == spv::DimBuffer && sampled == 1;
2374cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
2375cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
23765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2377cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeImage: {
2378cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Many descriptor types backing image types-- depends on dimension and whether the image will be used with a sampler.
2379cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // SPIRV for Vulkan requires that sampled be 1 or 2 -- leaving the decision to runtime is unacceptable.
2380cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            auto dim = type.word(3);
2381cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            auto sampled = type.word(7);
23825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2383cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (dim == spv::DimSubpassData) {
2384cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return descriptor_type == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
2385cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else if (dim == spv::DimBuffer) {
2386cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (sampled == 1) {
2387cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    return descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
2388cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                } else {
2389cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
2390cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
2391cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else if (sampled == 1) {
2392cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return descriptor_type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ||
2393cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                       descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
23945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else {
2395cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
23965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
23975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
23985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2399cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        // We shouldn't really see any other junk types -- but if we do, they're a mismatch.
2400cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
2401cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return false;  // Mismatch
24025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
24035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
24045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
24054110a6be7a8a287d459475926985f71c27d01298Chris Forbesstatic bool require_feature(debug_report_data *report_data, VkBool32 feature, char const *feature_name) {
2406a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    if (!feature) {
2407bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
2408cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    SHADER_CHECKER_FEATURE_NOT_ENABLED, "SC",
2409cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "Shader requires VkPhysicalDeviceFeatures::%s but is not "
2410cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "enabled on the device",
2411a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes                    feature_name)) {
2412a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes            return false;
2413a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes        }
2414a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    }
2415a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2416a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    return true;
2417a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes}
2418a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
241969f9a551bfb1fd5334950f9685c12c5adda23dfbChris Forbesstatic bool validate_shader_capabilities(debug_report_data *report_data, shader_module const *src,
242069f9a551bfb1fd5334950f9685c12c5adda23dfbChris Forbes                                         VkPhysicalDeviceFeatures const *enabledFeatures) {
2421e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool pass = true;
2422a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2423a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    for (auto insn : *src) {
2424a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes        if (insn.opcode() == spv::OpCapability) {
2425a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes            switch (insn.word(1)) {
2426cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityMatrix:
2427cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityShader:
2428cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityInputAttachment:
2429cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilitySampled1D:
2430cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityImage1D:
2431cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilitySampledBuffer:
2432cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityImageBuffer:
2433cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityImageQuery:
2434cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityDerivativeControl:
2435cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    // Always supported by a Vulkan 1.0 implementation -- no feature bits.
2436cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2437a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2438cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityGeometry:
2439cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->geometryShader, "geometryShader");
2440cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2441a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2442cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityTessellation:
2443cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->tessellationShader, "tessellationShader");
2444cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2445a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2446cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityFloat64:
2447cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderFloat64, "shaderFloat64");
2448cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2449a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2450cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityInt64:
2451cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderInt64, "shaderInt64");
2452cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2453a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2454cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityTessellationPointSize:
2455cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityGeometryPointSize:
2456cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderTessellationAndGeometryPointSize,
2457cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderTessellationAndGeometryPointSize");
2458cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2459a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2460cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityImageGatherExtended:
2461cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderImageGatherExtended, "shaderImageGatherExtended");
2462cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2463a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2464cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityStorageImageMultisample:
2465cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderStorageImageMultisample,
2466cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderStorageImageMultisample");
2467cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2468a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2469cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityUniformBufferArrayDynamicIndexing:
2470cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderUniformBufferArrayDynamicIndexing,
2471cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderUniformBufferArrayDynamicIndexing");
2472cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2473a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2474cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilitySampledImageArrayDynamicIndexing:
2475cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderSampledImageArrayDynamicIndexing,
2476cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderSampledImageArrayDynamicIndexing");
2477cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2478a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2479cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityStorageBufferArrayDynamicIndexing:
2480cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderStorageBufferArrayDynamicIndexing,
2481cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderStorageBufferArrayDynamicIndexing");
2482cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2483a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2484cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityStorageImageArrayDynamicIndexing:
2485cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderStorageImageArrayDynamicIndexing,
2486cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderStorageImageArrayDynamicIndexing");
2487cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2488a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2489cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityClipDistance:
2490cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderClipDistance, "shaderClipDistance");
2491cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2492a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2493cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityCullDistance:
2494cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderCullDistance, "shaderCullDistance");
2495cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2496a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2497cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityImageCubeArray:
2498cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->imageCubeArray, "imageCubeArray");
2499cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2500a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2501cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilitySampleRateShading:
2502cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->sampleRateShading, "sampleRateShading");
2503cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2504a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2505cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilitySparseResidency:
2506cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderResourceResidency, "shaderResourceResidency");
2507cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2508a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2509cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityMinLod:
2510cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderResourceMinLod, "shaderResourceMinLod");
2511cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2512a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2513cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilitySampledCubeArray:
2514cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->imageCubeArray, "imageCubeArray");
2515cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2516a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2517cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityImageMSArray:
2518cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderStorageImageMultisample,
2519cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderStorageImageMultisample");
2520cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2521a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2522cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityStorageImageExtendedFormats:
2523cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderStorageImageExtendedFormats,
2524cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderStorageImageExtendedFormats");
2525cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2526a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2527cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityInterpolationFunction:
2528cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->sampleRateShading, "sampleRateShading");
2529cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2530a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2531cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityStorageImageReadWithoutFormat:
2532cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderStorageImageReadWithoutFormat,
2533cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderStorageImageReadWithoutFormat");
2534cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2535a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2536cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityStorageImageWriteWithoutFormat:
2537cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderStorageImageWriteWithoutFormat,
2538cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderStorageImageWriteWithoutFormat");
2539cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2540a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2541cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityMultiViewport:
2542cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->multiViewport, "multiViewport");
2543cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2544a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2545cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                default:
2546cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
2547cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                SHADER_CHECKER_BAD_CAPABILITY, "SC", "Shader declares capability %u, not supported in Vulkan.",
2548cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                insn.word(1)))
2549cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        pass = false;
2550cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2551a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes            }
2552a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes        }
2553a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    }
2554a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2555a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    return pass;
2556a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes}
2557a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2558b2a61f3cd17c68887759817059fa1872f1e1464aChris Forbesstatic uint32_t descriptor_type_to_reqs(shader_module const *module, uint32_t type_id) {
25592aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes    auto type = module->get_def(type_id);
25602aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes
25612aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes    while (true) {
25622aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes        switch (type.opcode()) {
2563cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeArray:
2564cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeSampledImage:
2565cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                type = module->get_def(type.word(2));
2566cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
2567cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypePointer:
2568cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                type = module->get_def(type.word(3));
2569cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
2570cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeImage: {
2571cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto dim = type.word(3);
2572cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto arrayed = type.word(5);
2573cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto msaa = type.word(6);
2574cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski
2575cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                switch (dim) {
2576cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    case spv::Dim1D:
2577cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return arrayed ? DESCRIPTOR_REQ_VIEW_TYPE_1D_ARRAY : DESCRIPTOR_REQ_VIEW_TYPE_1D;
2578cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    case spv::Dim2D:
2579cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return (msaa ? DESCRIPTOR_REQ_MULTI_SAMPLE : DESCRIPTOR_REQ_SINGLE_SAMPLE) |
2580cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                               (arrayed ? DESCRIPTOR_REQ_VIEW_TYPE_2D_ARRAY : DESCRIPTOR_REQ_VIEW_TYPE_2D);
2581cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    case spv::Dim3D:
2582cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return DESCRIPTOR_REQ_VIEW_TYPE_3D;
2583cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    case spv::DimCube:
2584cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return arrayed ? DESCRIPTOR_REQ_VIEW_TYPE_CUBE_ARRAY : DESCRIPTOR_REQ_VIEW_TYPE_CUBE;
2585cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    case spv::DimSubpassData:
2586cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return msaa ? DESCRIPTOR_REQ_MULTI_SAMPLE : DESCRIPTOR_REQ_SINGLE_SAMPLE;
2587cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    default:  // buffer, etc.
2588cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return 0;
2589cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
25902aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes            }
2591cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
2592cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return 0;
25932aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes        }
25942aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes    }
2595b2a61f3cd17c68887759817059fa1872f1e1464aChris Forbes}
2596b2a61f3cd17c68887759817059fa1872f1e1464aChris Forbes
2597cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskistatic bool validate_pipeline_shader_stage(
2598cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    debug_report_data *report_data, VkPipelineShaderStageCreateInfo const *pStage, PIPELINE_STATE *pipeline,
2599cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    shader_module **out_module, spirv_inst_iter *out_entrypoint, VkPhysicalDeviceFeatures const *enabledFeatures,
2600cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    std::unordered_map<VkShaderModule, std::unique_ptr<shader_module>> const &shaderModuleMap) {
2601e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool pass = true;
260269f9a551bfb1fd5334950f9685c12c5adda23dfbChris Forbes    auto module_it = shaderModuleMap.find(pStage->module);
260369f9a551bfb1fd5334950f9685c12c5adda23dfbChris Forbes    auto module = *out_module = module_it->second.get();
260478be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
260525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Find the entrypoint
260678be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    auto entrypoint = *out_entrypoint = find_entrypoint(module, pStage->pName, pStage->stage);
260778be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    if (entrypoint == module->end()) {
26084f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes        if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__, VALIDATION_ERROR_00510,
26094f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                    "SC", "No entrypoint found named `%s` for stage %s. %s.", pStage->pName,
26104f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                    string_VkShaderStageFlagBits(pStage->stage), validation_error_map[VALIDATION_ERROR_00510])) {
2611cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return false;  // no point continuing beyond here, any analysis is just going to be garbage.
261278be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        }
261378be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    }
261478be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
261525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Validate shader capabilities against enabled device features
2616557cdd5218accf51ca894a14b7c6eeeb733f5cbbChris Forbes    pass &= validate_shader_capabilities(report_data, module, enabledFeatures);
261778be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
261825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Mark accessible ids
26193a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    auto accessible_ids = mark_accessible_ids(module, entrypoint);
262078be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
262125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Validate descriptor set layout against what the entrypoint actually uses
26223a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    auto descriptor_uses = collect_interface_by_descriptor_slot(report_data, module, accessible_ids);
262378be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
26242e0eca3d6fad72a29ae072e3895e29a2d2d66476Tobin Ehlis    auto pipelineLayout = pipeline->pipeline_layout;
2625ed399f66e0512ef077d0e0a7cb903248726d2424Chris Forbes
26260cfa9c3a1747749777581684536218f83c3977a9Chris Forbes    pass &= validate_specialization_offsets(report_data, pStage);
2627416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis    pass &= validate_push_constant_usage(report_data, &pipelineLayout.push_constant_ranges, module, accessible_ids, pStage->stage);
262878be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
262925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Validate descriptor use
263078be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    for (auto use : descriptor_uses) {
263178be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        // While validating shaders capture which slots are used by the pipeline
2632bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto &reqs = pipeline->active_slots[use.first.first][use.first.second];
2633b2a61f3cd17c68887759817059fa1872f1e1464aChris Forbes        reqs = descriptor_req(reqs | descriptor_type_to_reqs(module, use.second.type_id));
263478be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
263525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Verify given pipelineLayout has requested setLayout with requested binding
2636c8268861aaa8f9c47920065d6323e4609e5081b0Tobin Ehlis        const auto &binding = get_descriptor_binding(&pipelineLayout, use.first);
263778be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        unsigned required_descriptor_count;
263878be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
263978be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        if (!binding) {
2640bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
2641bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        SHADER_CHECKER_MISSING_DESCRIPTOR, "SC",
264278be5018e238bd464b1f1c55138df277c0c18922Chris Forbes                        "Shader uses descriptor slot %u.%u (used as type `%s`) but not declared in pipeline layout",
264378be5018e238bd464b1f1c55138df277c0c18922Chris Forbes                        use.first.first, use.first.second, describe_type(module, use.second.type_id).c_str())) {
2644e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                pass = false;
264578be5018e238bd464b1f1c55138df277c0c18922Chris Forbes            }
264678be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        } else if (~binding->stageFlags & pStage->stage) {
2647bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
2648cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        SHADER_CHECKER_DESCRIPTOR_NOT_ACCESSIBLE_FROM_STAGE, "SC",
2649cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "Shader uses descriptor slot %u.%u (used "
2650cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "as type `%s`) but descriptor not "
2651cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "accessible from stage %s",
2652fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis                        use.first.first, use.first.second, describe_type(module, use.second.type_id).c_str(),
265378be5018e238bd464b1f1c55138df277c0c18922Chris Forbes                        string_VkShaderStageFlagBits(pStage->stage))) {
2654e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                pass = false;
265578be5018e238bd464b1f1c55138df277c0c18922Chris Forbes            }
2656bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        } else if (!descriptor_type_match(module, use.second.type_id, binding->descriptorType, required_descriptor_count)) {
2657557cdd5218accf51ca894a14b7c6eeeb733f5cbbChris Forbes            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
2658cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        SHADER_CHECKER_DESCRIPTOR_TYPE_MISMATCH, "SC",
2659cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "Type mismatch on descriptor slot "
2660cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "%u.%u (used as type `%s`) but "
2661cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "descriptor of type %s",
2662fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis                        use.first.first, use.first.second, describe_type(module, use.second.type_id).c_str(),
266378be5018e238bd464b1f1c55138df277c0c18922Chris Forbes                        string_VkDescriptorType(binding->descriptorType))) {
2664e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                pass = false;
266578be5018e238bd464b1f1c55138df277c0c18922Chris Forbes            }
266678be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        } else if (binding->descriptorCount < required_descriptor_count) {
2667557cdd5218accf51ca894a14b7c6eeeb733f5cbbChris Forbes            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
2668fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis                        SHADER_CHECKER_DESCRIPTOR_TYPE_MISMATCH, "SC",
266978be5018e238bd464b1f1c55138df277c0c18922Chris Forbes                        "Shader expects at least %u descriptors for binding %u.%u (used as type `%s`) but only %u provided",
267078be5018e238bd464b1f1c55138df277c0c18922Chris Forbes                        required_descriptor_count, use.first.first, use.first.second,
2671fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis                        describe_type(module, use.second.type_id).c_str(), binding->descriptorCount)) {
2672e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                pass = false;
267378be5018e238bd464b1f1c55138df277c0c18922Chris Forbes            }
267478be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        }
267578be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    }
267678be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
267725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Validate use of input attachments against subpass structure
2678c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes    if (pStage->stage == VK_SHADER_STAGE_FRAGMENT_BIT) {
26793a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes        auto input_attachment_uses = collect_interface_by_input_attachment_index(report_data, module, accessible_ids);
2680c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes
2681c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes        auto rpci = pipeline->render_pass_ci.ptr();
2682c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes        auto subpass = pipeline->graphicsPipelineCI.subpass;
2683c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes
2684c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes        for (auto use : input_attachment_uses) {
2685c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes            auto input_attachments = rpci->pSubpasses[subpass].pInputAttachments;
2686bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            auto index = (input_attachments && use.first < rpci->pSubpasses[subpass].inputAttachmentCount)
2687bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             ? input_attachments[use.first].attachment
2688bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             : VK_ATTACHMENT_UNUSED;
2689c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes
2690c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes            if (index == VK_ATTACHMENT_UNUSED) {
2691c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
2692c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes                            SHADER_CHECKER_MISSING_INPUT_ATTACHMENT, "SC",
2693bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "Shader consumes input attachment index %d but not provided in subpass", use.first)) {
2694c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes                    pass = false;
2695c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes                }
2696bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            } else if (get_format_type(rpci->pAttachments[index].format) != get_fundamental_type(module, use.second.type_id)) {
2697eeb9f6a27f1acc11e54080fb3bcda7b513b5c89fChris Forbes                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
2698eeb9f6a27f1acc11e54080fb3bcda7b513b5c89fChris Forbes                            SHADER_CHECKER_INPUT_ATTACHMENT_TYPE_MISMATCH, "SC",
2699bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "Subpass input attachment %u format of %s does not match type used in shader `%s`", use.first,
2700bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            string_VkFormat(rpci->pAttachments[index].format), describe_type(module, use.second.type_id).c_str())) {
2701eeb9f6a27f1acc11e54080fb3bcda7b513b5c89fChris Forbes                    pass = false;
2702eeb9f6a27f1acc11e54080fb3bcda7b513b5c89fChris Forbes                }
2703eeb9f6a27f1acc11e54080fb3bcda7b513b5c89fChris Forbes            }
2704c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes        }
2705c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes    }
2706c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes
270778be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    return pass;
270878be5018e238bd464b1f1c55138df277c0c18922Chris Forbes}
270978be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
2710a61b537fcb6a4f7b92cd217b3964ad7a48109da1Tobin Ehlis// Validate that the shaders used by the given pipeline and store the active_slots
2711a61b537fcb6a4f7b92cd217b3964ad7a48109da1Tobin Ehlis//  that are actually used by the pipeline into pPipeline->active_slots
2712cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskistatic bool validate_and_capture_pipeline_shader_state(
2713cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    debug_report_data *report_data, PIPELINE_STATE *pPipeline, VkPhysicalDeviceFeatures const *enabledFeatures,
2714cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    std::unordered_map<VkShaderModule, unique_ptr<shader_module>> const &shaderModuleMap) {
27156660d6f3e4e4c895063e8d99098162bd2f508b24Chris Forbes    auto pCreateInfo = pPipeline->graphicsPipelineCI.ptr();
27165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    int vertex_stage = get_shader_stage_id(VK_SHADER_STAGE_VERTEX_BIT);
27175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    int fragment_stage = get_shader_stage_id(VK_SHADER_STAGE_FRAGMENT_BIT);
27185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    shader_module *shaders[5];
27205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    memset(shaders, 0, sizeof(shaders));
27215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter entrypoints[5];
27225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    memset(entrypoints, 0, sizeof(entrypoints));
27235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkPipelineVertexInputStateCreateInfo const *vi = 0;
2724e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool pass = true;
27255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) {
27276660d6f3e4e4c895063e8d99098162bd2f508b24Chris Forbes        auto pStage = &pCreateInfo->pStages[i];
272878be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        auto stage_id = get_shader_stage_id(pStage->stage);
2729bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pass &= validate_pipeline_shader_stage(report_data, pStage, pPipeline, &shaders[stage_id], &entrypoints[stage_id],
273069f9a551bfb1fd5334950f9685c12c5adda23dfbChris Forbes                                               enabledFeatures, shaderModuleMap);
27315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
27325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2733d5365427feb4a6c16371ecb651afa37b89dabd96Chris Forbes    // if the shader stages are no good individually, cross-stage validation is pointless.
2734cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!pass) return false;
2735b7476f4c4998ae20e579bd2d134667b71acdbf91Chris Forbes
27365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    vi = pCreateInfo->pVertexInputState;
27375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (vi) {
2739e4be8c69231df45752686575f22168b6d0fc5687Chris Forbes        pass &= validate_vi_consistency(report_data, vi);
27405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
27415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (shaders[vertex_stage]) {
2743e4be8c69231df45752686575f22168b6d0fc5687Chris Forbes        pass &= validate_vi_against_vs_inputs(report_data, vi, shaders[vertex_stage], entrypoints[vertex_stage]);
27445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
27455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    int producer = get_shader_stage_id(VK_SHADER_STAGE_VERTEX_BIT);
27475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    int consumer = get_shader_stage_id(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
27485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while (!shaders[producer] && producer != fragment_stage) {
27505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        producer++;
27515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        consumer++;
27525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
27535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (; producer != fragment_stage && consumer <= fragment_stage; consumer++) {
27555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        assert(shaders[producer]);
27565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (shaders[consumer]) {
2757bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            pass &= validate_interface_between_stages(report_data, shaders[producer], entrypoints[producer],
2758bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      &shader_stage_attribs[producer], shaders[consumer], entrypoints[consumer],
2759bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      &shader_stage_attribs[consumer]);
27605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            producer = consumer;
27625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
27635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
27645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27658da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis    if (shaders[fragment_stage]) {
2766e4be8c69231df45752686575f22168b6d0fc5687Chris Forbes        pass &= validate_fs_outputs_against_render_pass(report_data, shaders[fragment_stage], entrypoints[fragment_stage],
27678da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis                                                        pPipeline->render_pass_ci.ptr(), pCreateInfo->subpass);
27685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
27695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return pass;
27715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
27725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27734c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic bool validate_compute_pipeline(debug_report_data *report_data, PIPELINE_STATE *pPipeline,
27744c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis                                      VkPhysicalDeviceFeatures const *enabledFeatures,
27754c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis                                      std::unordered_map<VkShaderModule, unique_ptr<shader_module>> const &shaderModuleMap) {
27766660d6f3e4e4c895063e8d99098162bd2f508b24Chris Forbes    auto pCreateInfo = pPipeline->computePipelineCI.ptr();
277703857e826cdc6e8d814137fb3245596ca1cb7bc7Chris Forbes
277803857e826cdc6e8d814137fb3245596ca1cb7bc7Chris Forbes    shader_module *module;
277903857e826cdc6e8d814137fb3245596ca1cb7bc7Chris Forbes    spirv_inst_iter entrypoint;
278003857e826cdc6e8d814137fb3245596ca1cb7bc7Chris Forbes
2781bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    return validate_pipeline_shader_stage(report_data, &pCreateInfo->stage, pPipeline, &module, &entrypoint, enabledFeatures,
2782bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                          shaderModuleMap);
278303857e826cdc6e8d814137fb3245596ca1cb7bc7Chris Forbes}
27845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Return Set node ptr for specified set or else NULL
2785a682b1c533d9a492243b363c6585c4f03bcd87aaTobin Ehliscvdescriptorset::DescriptorSet *getSetNode(const layer_data *my_data, VkDescriptorSet set) {
2786104ab082916e41467ef60baaab7a5a8b2e02c59cTobin Ehlis    auto set_it = my_data->setMap.find(set);
2787104ab082916e41467ef60baaab7a5a8b2e02c59cTobin Ehlis    if (set_it == my_data->setMap.end()) {
27885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return NULL;
27895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2790104ab082916e41467ef60baaab7a5a8b2e02c59cTobin Ehlis    return set_it->second;
27915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
27925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2793eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young// For given pipeline, return number of MSAA samples, or one if MSAA disabled
27944c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic VkSampleCountFlagBits getNumSamples(PIPELINE_STATE const *pipe) {
2795ea8349eeee76ae2859c10870fd8bd9e60309eb28Chris Forbes    if (pipe->graphicsPipelineCI.pMultisampleState != NULL &&
2796ea8349eeee76ae2859c10870fd8bd9e60309eb28Chris Forbes        VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO == pipe->graphicsPipelineCI.pMultisampleState->sType) {
2797eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young        return pipe->graphicsPipelineCI.pMultisampleState->rasterizationSamples;
2798eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    }
2799eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    return VK_SAMPLE_COUNT_1_BIT;
2800eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young}
2801eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
2802bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic void list_bits(std::ostream &s, uint32_t bits) {
2803b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes    for (int i = 0; i < 32 && bits; i++) {
2804b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes        if (bits & (1 << i)) {
2805b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            s << i;
2806b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            bits &= ~(1 << i);
2807b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            if (bits) {
2808b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                s << ",";
2809b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            }
2810b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes        }
2811b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes    }
2812b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes}
2813b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes
2814eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young// Validate draw-time state related to the PSO
2815410598cceec2fd4fd53b470dd77c9ea6a001c181Tobin Ehlisstatic bool ValidatePipelineDrawtimeState(layer_data const *my_data, LAST_BOUND_STATE const &state, const GLOBAL_CB_NODE *pCB,
28164c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis                                          PIPELINE_STATE const *pPipeline) {
2817eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    bool skip_call = false;
281829d196e071b2dc1db47702085469396f2b956820Chris Forbes
2819d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen    // Verify vertex binding
282029d196e071b2dc1db47702085469396f2b956820Chris Forbes    if (pPipeline->vertexBindingDescriptions.size() > 0) {
282129d196e071b2dc1db47702085469396f2b956820Chris Forbes        for (size_t i = 0; i < pPipeline->vertexBindingDescriptions.size(); i++) {
2822312129ec52e6249aa453e27e6be17a8dab1e98b8Tobin Ehlis            auto vertex_binding = pPipeline->vertexBindingDescriptions[i].binding;
2823312129ec52e6249aa453e27e6be17a8dab1e98b8Tobin Ehlis            if ((pCB->currentDrawData.buffers.size() < (vertex_binding + 1)) ||
2824312129ec52e6249aa453e27e6be17a8dab1e98b8Tobin Ehlis                (pCB->currentDrawData.buffers[vertex_binding] == VK_NULL_HANDLE)) {
2825cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                skip_call |=
2826cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
2827cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            DRAWSTATE_VTX_INDEX_OUT_OF_BOUNDS, "DS",
2828cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "The Pipeline State Object (0x%" PRIxLEAST64
2829cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            ") expects that this Command Buffer's vertex binding Index %u "
2830cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "should be set via vkCmdBindVertexBuffers. This is because VkVertexInputBindingDescription struct "
2831cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "at index " PRINTF_SIZE_T_SPECIFIER " of pVertexBindingDescriptions has a binding value of %u.",
2832cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            (uint64_t)state.pipeline_state->pipeline, vertex_binding, i, vertex_binding);
283329d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
283429d196e071b2dc1db47702085469396f2b956820Chris Forbes        }
283529d196e071b2dc1db47702085469396f2b956820Chris Forbes    } else {
283658b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis        if (!pCB->currentDrawData.buffers.empty() && !pCB->vertex_buffer_used) {
283729d196e071b2dc1db47702085469396f2b956820Chris Forbes            skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0,
28385c288f35b2eab0dab95d18768235fef6ffd69b30Tobin Ehlis                                 0, __LINE__, DRAWSTATE_VTX_INDEX_OUT_OF_BOUNDS, "DS",
2839226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                 "Vertex buffers are bound to command buffer (0x%p"
28405c288f35b2eab0dab95d18768235fef6ffd69b30Tobin Ehlis                                 ") but no vertex buffers are attached to this Pipeline State Object (0x%" PRIxLEAST64 ").",
2841226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                 pCB->commandBuffer, (uint64_t)state.pipeline_state->pipeline);
284229d196e071b2dc1db47702085469396f2b956820Chris Forbes        }
284329d196e071b2dc1db47702085469396f2b956820Chris Forbes    }
284429d196e071b2dc1db47702085469396f2b956820Chris Forbes    // If Viewport or scissors are dynamic, verify that dynamic count matches PSO count.
284529d196e071b2dc1db47702085469396f2b956820Chris Forbes    // Skip check if rasterization is disabled or there is no viewport.
284629d196e071b2dc1db47702085469396f2b956820Chris Forbes    if ((!pPipeline->graphicsPipelineCI.pRasterizationState ||
284729d196e071b2dc1db47702085469396f2b956820Chris Forbes         (pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable == VK_FALSE)) &&
284829d196e071b2dc1db47702085469396f2b956820Chris Forbes        pPipeline->graphicsPipelineCI.pViewportState) {
284929d196e071b2dc1db47702085469396f2b956820Chris Forbes        bool dynViewport = isDynamic(pPipeline, VK_DYNAMIC_STATE_VIEWPORT);
285029d196e071b2dc1db47702085469396f2b956820Chris Forbes        bool dynScissor = isDynamic(pPipeline, VK_DYNAMIC_STATE_SCISSOR);
2851b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes
285229d196e071b2dc1db47702085469396f2b956820Chris Forbes        if (dynViewport) {
2853b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            auto requiredViewportsMask = (1 << pPipeline->graphicsPipelineCI.pViewportState->viewportCount) - 1;
2854b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            auto missingViewportMask = ~pCB->viewportMask & requiredViewportsMask;
2855b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            if (missingViewportMask) {
2856b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                std::stringstream ss;
2857b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                ss << "Dynamic viewport(s) ";
2858b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                list_bits(ss, missingViewportMask);
2859d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen                ss << " are used by pipeline state object, but were not provided via calls to vkCmdSetViewport().";
2860b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
2861bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                     __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", "%s", ss.str().c_str());
286229d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
286329d196e071b2dc1db47702085469396f2b956820Chris Forbes        }
2864b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes
286529d196e071b2dc1db47702085469396f2b956820Chris Forbes        if (dynScissor) {
2866b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            auto requiredScissorMask = (1 << pPipeline->graphicsPipelineCI.pViewportState->scissorCount) - 1;
2867b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            auto missingScissorMask = ~pCB->scissorMask & requiredScissorMask;
2868b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            if (missingScissorMask) {
2869b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                std::stringstream ss;
2870b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                ss << "Dynamic scissor(s) ";
2871b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                list_bits(ss, missingScissorMask);
2872d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen                ss << " are used by pipeline state object, but were not provided via calls to vkCmdSetScissor().";
2873b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
2874bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                     __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", "%s", ss.str().c_str());
287529d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
287629d196e071b2dc1db47702085469396f2b956820Chris Forbes        }
287729d196e071b2dc1db47702085469396f2b956820Chris Forbes    }
287829d196e071b2dc1db47702085469396f2b956820Chris Forbes
287929d196e071b2dc1db47702085469396f2b956820Chris Forbes    // Verify that any MSAA request in PSO matches sample# in bound FB
288029d196e071b2dc1db47702085469396f2b956820Chris Forbes    // Skip the check if rasterization is disabled.
288129d196e071b2dc1db47702085469396f2b956820Chris Forbes    if (!pPipeline->graphicsPipelineCI.pRasterizationState ||
288229d196e071b2dc1db47702085469396f2b956820Chris Forbes        (pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable == VK_FALSE)) {
288329d196e071b2dc1db47702085469396f2b956820Chris Forbes        VkSampleCountFlagBits pso_num_samples = getNumSamples(pPipeline);
288429d196e071b2dc1db47702085469396f2b956820Chris Forbes        if (pCB->activeRenderPass) {
2885fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes            auto const render_pass_info = pCB->activeRenderPass->createInfo.ptr();
288629d196e071b2dc1db47702085469396f2b956820Chris Forbes            const VkSubpassDescription *subpass_desc = &render_pass_info->pSubpasses[pCB->activeSubpass];
288729d196e071b2dc1db47702085469396f2b956820Chris Forbes            uint32_t i;
288829d196e071b2dc1db47702085469396f2b956820Chris Forbes
288929d196e071b2dc1db47702085469396f2b956820Chris Forbes            const safe_VkPipelineColorBlendStateCreateInfo *color_blend_state = pPipeline->graphicsPipelineCI.pColorBlendState;
289029d196e071b2dc1db47702085469396f2b956820Chris Forbes            if ((color_blend_state != NULL) && (pCB->activeSubpass == pPipeline->graphicsPipelineCI.subpass) &&
289129d196e071b2dc1db47702085469396f2b956820Chris Forbes                (color_blend_state->attachmentCount != subpass_desc->colorAttachmentCount)) {
289229d196e071b2dc1db47702085469396f2b956820Chris Forbes                skip_call |=
2893bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2894bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            reinterpret_cast<const uint64_t &>(pPipeline->pipeline), __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
2895bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "Render pass subpass %u mismatch with blending state defined and blend state attachment "
2896cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "count %u while subpass color attachment count %u in Pipeline (0x%" PRIxLEAST64
2897cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            ")!  These "
2898bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "must be the same at draw-time.",
2899bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            pCB->activeSubpass, color_blend_state->attachmentCount, subpass_desc->colorAttachmentCount,
2900bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            reinterpret_cast<const uint64_t &>(pPipeline->pipeline));
290129d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
2902eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
290376957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes            unsigned subpass_num_samples = 0;
29040a7ed0466d3d3c6c71be07d66c200482d9a9d073Chris Forbes
290529d196e071b2dc1db47702085469396f2b956820Chris Forbes            for (i = 0; i < subpass_desc->colorAttachmentCount; i++) {
290676957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                auto attachment = subpass_desc->pColorAttachments[i].attachment;
290776957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                if (attachment != VK_ATTACHMENT_UNUSED)
290876957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                    subpass_num_samples |= (unsigned)render_pass_info->pAttachments[attachment].samples;
290929d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
29100a7ed0466d3d3c6c71be07d66c200482d9a9d073Chris Forbes
291176957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes            if (subpass_desc->pDepthStencilAttachment &&
291276957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                subpass_desc->pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
291376957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                auto attachment = subpass_desc->pDepthStencilAttachment->attachment;
291476957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                subpass_num_samples |= (unsigned)render_pass_info->pAttachments[attachment].samples;
291529d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
2916eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
29170dc3fd4e57b8531638781daa01a2fb5d1048a6fbJamie Madill            if (subpass_num_samples && static_cast<unsigned>(pso_num_samples) != subpass_num_samples) {
291829d196e071b2dc1db47702085469396f2b956820Chris Forbes                skip_call |=
2919bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2920bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            reinterpret_cast<const uint64_t &>(pPipeline->pipeline), __LINE__, DRAWSTATE_NUM_SAMPLES_MISMATCH, "DS",
2921bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "Num samples mismatch! At draw-time in Pipeline (0x%" PRIxLEAST64
2922bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            ") with %u samples while current RenderPass (0x%" PRIxLEAST64 ") w/ %u samples!",
2923bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            reinterpret_cast<const uint64_t &>(pPipeline->pipeline), pso_num_samples,
2924bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            reinterpret_cast<const uint64_t &>(pCB->activeRenderPass->renderPass), subpass_num_samples);
2925eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young            }
292629d196e071b2dc1db47702085469396f2b956820Chris Forbes        } else {
292729d196e071b2dc1db47702085469396f2b956820Chris Forbes            skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2928bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 reinterpret_cast<const uint64_t &>(pPipeline->pipeline), __LINE__, DRAWSTATE_NUM_SAMPLES_MISMATCH,
2929bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 "DS", "No active render pass found at draw-time in Pipeline (0x%" PRIxLEAST64 ")!",
293029d196e071b2dc1db47702085469396f2b956820Chris Forbes                                 reinterpret_cast<const uint64_t &>(pPipeline->pipeline));
2931eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young        }
2932eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    }
2933528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis    // Verify that PSO creation renderPass is compatible with active renderPass
2934528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis    if (pCB->activeRenderPass) {
2935528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis        std::string err_string;
2936a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        if ((pCB->activeRenderPass->renderPass != pPipeline->graphicsPipelineCI.renderPass) &&
2937fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes            !verify_renderpass_compatibility(my_data, pCB->activeRenderPass->createInfo.ptr(), pPipeline->render_pass_ci.ptr(),
2938528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis                                             err_string)) {
2939528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis            // renderPass that PSO was created with must be compatible with active renderPass that PSO is being used with
2940528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis            skip_call |=
2941528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis                log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2942528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis                        reinterpret_cast<const uint64_t &>(pPipeline->pipeline), __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE, "DS",
2943cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "At Draw time the active render pass (0x%" PRIxLEAST64
2944cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        ") is incompatible w/ gfx pipeline "
2945528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis                        "(0x%" PRIxLEAST64 ") that was created w/ render pass (0x%" PRIxLEAST64 ") due to: %s",
29466de0e43adfbd3c049252412d998524e7edbd3796Chris Forbes                        reinterpret_cast<uint64_t &>(pCB->activeRenderPass->renderPass),
29476de0e43adfbd3c049252412d998524e7edbd3796Chris Forbes                        reinterpret_cast<uint64_t const &>(pPipeline->pipeline),
2948528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis                        reinterpret_cast<const uint64_t &>(pPipeline->graphicsPipelineCI.renderPass), err_string.c_str());
2949528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis        }
2950c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes
2951c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes        if (pPipeline->graphicsPipelineCI.subpass != pCB->activeSubpass) {
2952c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes            skip_call |=
2953c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes                log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2954c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes                        reinterpret_cast<uint64_t const &>(pPipeline->pipeline), __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE, "DS",
2955c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes                        "Pipeline was built for subpass %u but used in subpass %u", pPipeline->graphicsPipelineCI.subpass,
2956c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes                        pCB->activeSubpass);
2957c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes        }
2958528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis    }
295929d196e071b2dc1db47702085469396f2b956820Chris Forbes    // TODO : Add more checks here
296029d196e071b2dc1db47702085469396f2b956820Chris Forbes
2961eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    return skip_call;
2962eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young}
2963eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
29645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Validate overall state at the time of a draw call
29651c130ea631a82716dc7334de17767536525f2292Tobin Ehlisstatic bool ValidateDrawState(layer_data *my_data, GLOBAL_CB_NODE *cb_node, const bool indexed,
29664f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                              const VkPipelineBindPoint bind_point, const char *function,
29674f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                              UNIQUE_VALIDATION_ERROR_CODE const msg_code) {
2968e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool result = false;
29691c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    auto const &state = cb_node->lastBound[bind_point];
29704c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    PIPELINE_STATE *pPipe = state.pipeline_state;
297122fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis    if (nullptr == pPipe) {
297222fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis        result |= log_msg(
297322fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis            my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
297422fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis            DRAWSTATE_INVALID_PIPELINE, "DS",
297522fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis            "At Draw/Dispatch time no valid VkPipeline is bound! This is illegal. Please bind one with vkCmdBindPipeline().");
297622fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis        // Early return as any further checks below will be busted w/o a pipeline
2977cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (result) return true;
297822fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis    }
29793d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    // First check flag states
29801c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    if (VK_PIPELINE_BIND_POINT_GRAPHICS == bind_point)
29814f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes        result = validate_draw_state_flags(my_data, cb_node, pPipe, indexed, msg_code);
29827a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis
29835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Now complete other state checks
298469b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis    if (VK_NULL_HANDLE != state.pipeline_layout.layout) {
298522fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis        string errorString;
298669b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis        auto pipeline_layout = pPipe->pipeline_layout;
2987169c4506062f06d6676eb4da3c9e0437d1d9d659Chris Forbes
29881c130ea631a82716dc7334de17767536525f2292Tobin Ehlis        for (const auto &set_binding_pair : pPipe->active_slots) {
29891c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            uint32_t setIndex = set_binding_pair.first;
299022fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis            // If valid set is not bound throw an error
299122fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis            if ((state.boundDescriptorSets.size() <= setIndex) || (!state.boundDescriptorSets[setIndex])) {
299222fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
299322fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                                  DRAWSTATE_DESCRIPTOR_SET_NOT_BOUND, "DS",
2994bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                  "VkPipeline 0x%" PRIxLEAST64 " uses set #%u but that set is not bound.",
2995bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                  (uint64_t)pPipe->pipeline, setIndex);
299669b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis            } else if (!verify_set_layout_compatibility(my_data, state.boundDescriptorSets[setIndex], &pipeline_layout, setIndex,
299769b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                                                        errorString)) {
299869b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                // Set is bound but not compatible w/ overlapping pipeline_layout from PSO
299971511c5a10533c910bfe62c3bcf58e2a4054e7acTobin Ehlis                VkDescriptorSet setHandle = state.boundDescriptorSets[setIndex]->GetSet();
300022fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                result |=
300122fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                    log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
300222fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                            (uint64_t)setHandle, __LINE__, DRAWSTATE_PIPELINE_LAYOUTS_INCOMPATIBLE, "DS",
3003414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                            "VkDescriptorSet (0x%" PRIxLEAST64
3004414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                            ") bound as set #%u is not compatible with overlapping VkPipelineLayout 0x%" PRIxLEAST64 " due to: %s",
300569b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                            reinterpret_cast<uint64_t &>(setHandle), setIndex, reinterpret_cast<uint64_t &>(pipeline_layout.layout),
300669b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                            errorString.c_str());
3007cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else {  // Valid set is bound and layout compatible, validate that it's updated
300822fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                // Pull the set node
30091c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                cvdescriptorset::DescriptorSet *descriptor_set = state.boundDescriptorSets[setIndex];
3010aa21bc3b3c5c7adfeb488fc80bdcb339d63615b8Tobin Ehlis                // Gather active bindings
3011ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                std::unordered_set<uint32_t> active_bindings;
30121c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                for (auto binding : set_binding_pair.second) {
3013ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                    active_bindings.insert(binding.first);
3014aa21bc3b3c5c7adfeb488fc80bdcb339d63615b8Tobin Ehlis                }
301522fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                // Make sure set has been updated if it has no immutable samplers
301622fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                //  If it has immutable samplers, we'll flag error later as needed depending on binding
30171c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                if (!descriptor_set->IsUpdated()) {
3018ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                    for (auto binding : active_bindings) {
30191c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                        if (!descriptor_set->GetImmutableSamplerPtrFromBinding(binding)) {
3020cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
3021cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                              VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)descriptor_set->GetSet(),
3022cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                              __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS",
3023cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                              "Descriptor Set 0x%" PRIxLEAST64
3024cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                              " bound but was never updated. It is now being used to draw so "
3025cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                              "this will result in undefined behavior.",
3026cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                              (uint64_t)descriptor_set->GetSet());
3027fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis                        }
30285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
30295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
30307433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis                // Validate the draw-time state for this descriptor set
30317433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis                std::string err_str;
30321c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                if (!descriptor_set->ValidateDrawState(set_binding_pair.second, state.dynamicOffsets[setIndex], &err_str)) {
30331c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                    auto set = descriptor_set->GetSet();
30347433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis                    result |=
30357433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis                        log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
30367433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis                                reinterpret_cast<const uint64_t &>(set), __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS",
30377433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis                                "Descriptor set 0x%" PRIxLEAST64 " encountered the following validation error at %s() time: %s",
30387433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis                                reinterpret_cast<const uint64_t &>(set), function, err_str.c_str());
30397433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis                }
30405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
304122fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis        }
304222fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis    }
3043eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
3044eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    // Check general pipeline state that needs to be validated at drawtime
3045cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (VK_PIPELINE_BIND_POINT_GRAPHICS == bind_point) result |= ValidatePipelineDrawtimeState(my_data, state, cb_node, pPipe);
3046eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
30475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
30485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
30495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
30501c130ea631a82716dc7334de17767536525f2292Tobin Ehlisstatic void UpdateDrawState(layer_data *my_data, GLOBAL_CB_NODE *cb_state, const VkPipelineBindPoint bind_point) {
30511c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    auto const &state = cb_state->lastBound[bind_point];
3052ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis    PIPELINE_STATE *pPipe = state.pipeline_state;
3053ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis    if (VK_NULL_HANDLE != state.pipeline_layout.layout) {
30541c130ea631a82716dc7334de17767536525f2292Tobin Ehlis        for (const auto &set_binding_pair : pPipe->active_slots) {
30551c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            uint32_t setIndex = set_binding_pair.first;
3056ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis            // Pull the set node
30571c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            cvdescriptorset::DescriptorSet *descriptor_set = state.boundDescriptorSets[setIndex];
3058ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis            // Bind this set and its active descriptor resources to the command buffer
30591c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            descriptor_set->BindCommandBuffer(cb_state, set_binding_pair.second);
30607433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis            // For given active slots record updated images & buffers
30611c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            descriptor_set->GetStorageUpdates(set_binding_pair.second, &cb_state->updateBuffers, &cb_state->updateImages);
3062ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis        }
3063ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis    }
306458b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    if (pPipe->vertexBindingDescriptions.size() > 0) {
306558b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis        cb_state->vertex_buffer_used = true;
306658b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    }
3067ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis}
3068ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis
3069a27508babf63d50aea75883a3702979193c23683Mark Young// Validate HW line width capabilities prior to setting requested line width.
3070a27508babf63d50aea75883a3702979193c23683Mark Youngstatic bool verifyLineWidth(layer_data *my_data, DRAW_STATE_ERROR dsError, const uint64_t &target, float lineWidth) {
3071a27508babf63d50aea75883a3702979193c23683Mark Young    bool skip_call = false;
3072a27508babf63d50aea75883a3702979193c23683Mark Young
3073a27508babf63d50aea75883a3702979193c23683Mark Young    // First check to see if the physical device supports wide lines.
3074f71dd305f197826a61f398bff725267a20ea1d90Chris Forbes    if ((VK_FALSE == my_data->enabled_features.wideLines) && (1.0f != lineWidth)) {
3075a27508babf63d50aea75883a3702979193c23683Mark Young        skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, target, __LINE__,
3076cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             dsError, "DS",
3077cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "Attempt to set lineWidth to %f but physical device wideLines feature "
3078cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "not supported/enabled so lineWidth must be 1.0f!",
3079a27508babf63d50aea75883a3702979193c23683Mark Young                             lineWidth);
3080a27508babf63d50aea75883a3702979193c23683Mark Young    } else {
3081a27508babf63d50aea75883a3702979193c23683Mark Young        // Otherwise, make sure the width falls in the valid range.
3082a27508babf63d50aea75883a3702979193c23683Mark Young        if ((my_data->phys_dev_properties.properties.limits.lineWidthRange[0] > lineWidth) ||
3083a27508babf63d50aea75883a3702979193c23683Mark Young            (my_data->phys_dev_properties.properties.limits.lineWidthRange[1] < lineWidth)) {
3084a27508babf63d50aea75883a3702979193c23683Mark Young            skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, target,
3085cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 __LINE__, dsError, "DS",
3086cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "Attempt to set lineWidth to %f but physical device limits line width "
3087cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "to between [%f, %f]!",
3088a27508babf63d50aea75883a3702979193c23683Mark Young                                 lineWidth, my_data->phys_dev_properties.properties.limits.lineWidthRange[0],
3089a27508babf63d50aea75883a3702979193c23683Mark Young                                 my_data->phys_dev_properties.properties.limits.lineWidthRange[1]);
3090a27508babf63d50aea75883a3702979193c23683Mark Young        }
3091a27508babf63d50aea75883a3702979193c23683Mark Young    }
3092a27508babf63d50aea75883a3702979193c23683Mark Young
3093a27508babf63d50aea75883a3702979193c23683Mark Young    return skip_call;
3094a27508babf63d50aea75883a3702979193c23683Mark Young}
3095a27508babf63d50aea75883a3702979193c23683Mark Young
30965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Verify that create state for a pipeline is valid
30975c60b2a2a1dcfe8f977226eaced004c522d19d49Mark Lobodzinskistatic bool verifyPipelineCreateState(layer_data *my_data, std::vector<PIPELINE_STATE *> pPipelines, int pipelineIndex) {
309883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
30995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
31004c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    PIPELINE_STATE *pPipeline = pPipelines[pipelineIndex];
31015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
31025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If create derivative bit is set, check that we've specified a base
31035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // pipeline correctly, and that the base pipeline was created to allow
31045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // derivatives.
31055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pPipeline->graphicsPipelineCI.flags & VK_PIPELINE_CREATE_DERIVATIVE_BIT) {
31064c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis        PIPELINE_STATE *pBasePipeline = nullptr;
31075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!((pPipeline->graphicsPipelineCI.basePipelineHandle != VK_NULL_HANDLE) ^
31085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis              (pPipeline->graphicsPipelineCI.basePipelineIndex != -1))) {
3109f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt            // This check is a superset of VALIDATION_ERROR_00526 and VALIDATION_ERROR_00528
311083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
311183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
311283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 "Invalid Pipeline CreateInfo: exactly one of base pipeline index and handle must be specified");
31135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (pPipeline->graphicsPipelineCI.basePipelineIndex != -1) {
31145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (pPipeline->graphicsPipelineCI.basePipelineIndex >= pipelineIndex) {
311583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                skip_call |=
31165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3117f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                            VALIDATION_ERROR_00518, "DS",
3118f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                            "Invalid Pipeline CreateInfo: base pipeline must occur earlier in array than derivative pipeline. %s",
3119f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                            validation_error_map[VALIDATION_ERROR_00518]);
31205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else {
31215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pBasePipeline = pPipelines[pPipeline->graphicsPipelineCI.basePipelineIndex];
31225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
31235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (pPipeline->graphicsPipelineCI.basePipelineHandle != VK_NULL_HANDLE) {
31244c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis            pBasePipeline = getPipelineState(my_data, pPipeline->graphicsPipelineCI.basePipelineHandle);
31255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
31265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
31275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (pBasePipeline && !(pBasePipeline->graphicsPipelineCI.flags & VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT)) {
312883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
312983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
313083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 "Invalid Pipeline CreateInfo: base pipeline does not allow derivatives.");
31315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
31325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
31335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
31345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pPipeline->graphicsPipelineCI.pColorBlendState != NULL) {
3135f71dd305f197826a61f398bff725267a20ea1d90Chris Forbes        if (!my_data->enabled_features.independentBlend) {
31363d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis            if (pPipeline->attachments.size() > 1) {
313726c548826ff0f83d12c769b51e7d6f76d1265c0eChris Forbes                VkPipelineColorBlendAttachmentState *pAttachments = &pPipeline->attachments[0];
3138c7bd67f06427b08ba65cdf2dd529c8234beebdd5Mark Lobodzinski                for (size_t i = 1; i < pPipeline->attachments.size(); i++) {
313906811df0256552cd7da9d7297672af377463fc4aMark Mueller                    // Quoting the spec: "If [the independent blend] feature is not enabled, the VkPipelineColorBlendAttachmentState
314006811df0256552cd7da9d7297672af377463fc4aMark Mueller                    // settings for all color attachments must be identical." VkPipelineColorBlendAttachmentState contains
314106811df0256552cd7da9d7297672af377463fc4aMark Mueller                    // only attachment state, so memcmp is best suited for the comparison
314206811df0256552cd7da9d7297672af377463fc4aMark Mueller                    if (memcmp(static_cast<const void *>(pAttachments), static_cast<const void *>(&pAttachments[i]),
314306811df0256552cd7da9d7297672af377463fc4aMark Mueller                               sizeof(pAttachments[0]))) {
3144cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
3145cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                             __LINE__, VALIDATION_ERROR_01532, "DS",
3146cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                             "Invalid Pipeline CreateInfo: If independent blend feature not "
3147cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                             "enabled, all elements of pAttachments must be identical. %s",
3148cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                             validation_error_map[VALIDATION_ERROR_01532]);
314906811df0256552cd7da9d7297672af377463fc4aMark Mueller                        break;
3150c7bd67f06427b08ba65cdf2dd529c8234beebdd5Mark Lobodzinski                    }
31515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
31525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
31535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
3154bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        if (!my_data->enabled_features.logicOp && (pPipeline->graphicsPipelineCI.pColorBlendState->logicOpEnable != VK_FALSE)) {
315583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |=
31565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3157f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                        VALIDATION_ERROR_01533, "DS",
3158f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                        "Invalid Pipeline CreateInfo: If logic operations feature not enabled, logicOpEnable must be VK_FALSE. %s",
3159f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                        validation_error_map[VALIDATION_ERROR_01533]);
31605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
31615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
31625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3163a61b537fcb6a4f7b92cd217b3964ad7a48109da1Tobin Ehlis    // Ensure the subpass index is valid. If not, then validate_and_capture_pipeline_shader_state
31645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // produces nonsense errors that confuse users. Other layers should already
31655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // emit errors for renderpass being invalid.
3166127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis    auto renderPass = getRenderPassState(my_data, pPipeline->graphicsPipelineCI.renderPass);
3167fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    if (renderPass && pPipeline->graphicsPipelineCI.subpass >= renderPass->createInfo.subpassCount) {
316883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis        skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3169cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             VALIDATION_ERROR_02122, "DS",
3170cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "Invalid Pipeline CreateInfo State: Subpass index %u "
3171cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "is out of range for this renderpass (0..%u). %s",
3172f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             pPipeline->graphicsPipelineCI.subpass, renderPass->createInfo.subpassCount - 1,
3173f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             validation_error_map[VALIDATION_ERROR_02122]);
31745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
31755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3176f71dd305f197826a61f398bff725267a20ea1d90Chris Forbes    if (!validate_and_capture_pipeline_shader_state(my_data->report_data, pPipeline, &my_data->enabled_features,
317769f9a551bfb1fd5334950f9685c12c5adda23dfbChris Forbes                                                    my_data->shaderModuleMap)) {
317883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis        skip_call = true;
31795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
318052156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes    // Each shader's stage must be unique
318152156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes    if (pPipeline->duplicate_shaders) {
318252156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes        for (uint32_t stage = VK_SHADER_STAGE_VERTEX_BIT; stage & VK_SHADER_STAGE_ALL_GRAPHICS; stage <<= 1) {
318352156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes            if (pPipeline->duplicate_shaders & stage) {
318483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
318583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                     __LINE__, DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
318683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                     "Invalid Pipeline CreateInfo State: Multiple shaders provided for stage %s",
318783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                     string_VkShaderStageFlagBits(VkShaderStageFlagBits(stage)));
318852156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes            }
318952156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes        }
319052156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes    }
31915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // VS is required
31925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (!(pPipeline->active_shaders & VK_SHADER_STAGE_VERTEX_BIT)) {
3193f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt        skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3194f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             VALIDATION_ERROR_00532, "DS", "Invalid Pipeline CreateInfo State: Vertex Shader required. %s",
3195f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             validation_error_map[VALIDATION_ERROR_00532]);
31965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
31975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Either both or neither TC/TE shaders should be defined
3198f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    if ((pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) &&
3199f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt        !(pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)) {
3200f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt        skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3201f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             VALIDATION_ERROR_00534, "DS",
3202f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             "Invalid Pipeline CreateInfo State: TE and TC shaders must be included or excluded as a pair. %s",
3203f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             validation_error_map[VALIDATION_ERROR_00534]);
3204f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    }
3205f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    if (!(pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) &&
3206f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt        (pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)) {
320783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis        skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3208f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             VALIDATION_ERROR_00535, "DS",
3209f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             "Invalid Pipeline CreateInfo State: TE and TC shaders must be included or excluded as a pair. %s",
3210f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             validation_error_map[VALIDATION_ERROR_00535]);
32115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
32125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Compute shaders should be specified independent of Gfx shaders
3213f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    if (pPipeline->active_shaders & VK_SHADER_STAGE_COMPUTE_BIT) {
321483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis        skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3215f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             VALIDATION_ERROR_00533, "DS",
3216f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             "Invalid Pipeline CreateInfo State: Do not specify Compute Shader for Gfx Pipeline. %s",
3217f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             validation_error_map[VALIDATION_ERROR_00533]);
32185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
32195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive topology is only valid for tessellation pipelines.
32205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Mismatching primitive topology and tessellation fails graphics pipeline creation.
32215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pPipeline->active_shaders & (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) &&
3222ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        (!pPipeline->graphicsPipelineCI.pInputAssemblyState ||
3223ca546210846c65808717f8875deae39bd227c240Tobin Ehlis         pPipeline->graphicsPipelineCI.pInputAssemblyState->topology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST)) {
322483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis        skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3225cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             VALIDATION_ERROR_02099, "DS",
3226cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "Invalid Pipeline CreateInfo State: "
3227cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST must be set as IA "
3228cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "topology for tessellation pipelines. %s",
3229f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             validation_error_map[VALIDATION_ERROR_02099]);
32305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
3231ca546210846c65808717f8875deae39bd227c240Tobin Ehlis    if (pPipeline->graphicsPipelineCI.pInputAssemblyState &&
3232ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        pPipeline->graphicsPipelineCI.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) {
32335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (~pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) {
323483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3235cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 VALIDATION_ERROR_02100, "DS",
3236cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "Invalid Pipeline CreateInfo State: "
3237cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive "
3238cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "topology is only valid for tessellation pipelines. %s",
3239f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                                 validation_error_map[VALIDATION_ERROR_02100]);
32405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
32415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
3242f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt
3243f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    if (pPipeline->graphicsPipelineCI.pTessellationState &&
3244f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt        ((pPipeline->graphicsPipelineCI.pTessellationState->patchControlPoints == 0) ||
3245f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt         (pPipeline->graphicsPipelineCI.pTessellationState->patchControlPoints >
3246f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt          my_data->phys_dev_properties.properties.limits.maxTessellationPatchSize))) {
3247f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt        skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3248cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             VALIDATION_ERROR_01426, "DS",
3249cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "Invalid Pipeline CreateInfo State: "
3250cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive "
3251cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "topology used with patchControlPoints value %u."
3252cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             " patchControlPoints should be >0 and <=%u. %s",
3253f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             pPipeline->graphicsPipelineCI.pTessellationState->patchControlPoints,
3254f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             my_data->phys_dev_properties.properties.limits.maxTessellationPatchSize,
3255f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             validation_error_map[VALIDATION_ERROR_01426]);
3256f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    }
3257f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt
3258a27508babf63d50aea75883a3702979193c23683Mark Young    // If a rasterization state is provided, make sure that the line width conforms to the HW.
3259a27508babf63d50aea75883a3702979193c23683Mark Young    if (pPipeline->graphicsPipelineCI.pRasterizationState) {
3260a27508babf63d50aea75883a3702979193c23683Mark Young        if (!isDynamic(pPipeline, VK_DYNAMIC_STATE_LINE_WIDTH)) {
32616de0e43adfbd3c049252412d998524e7edbd3796Chris Forbes            skip_call |= verifyLineWidth(my_data, DRAWSTATE_INVALID_PIPELINE_CREATE_STATE,
32626de0e43adfbd3c049252412d998524e7edbd3796Chris Forbes                                         reinterpret_cast<uint64_t const &>(pPipeline->pipeline),
326383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                         pPipeline->graphicsPipelineCI.pRasterizationState->lineWidth);
3264a27508babf63d50aea75883a3702979193c23683Mark Young        }
3265a27508babf63d50aea75883a3702979193c23683Mark Young    }
32665dcdd90e54199dfeb29938a3a03d998397c22664Chris Forbes
3267dcfa519862e3ee788cf008388cc6b66832f74477Mark Lobodzinski    // If rasterization is not disabled and subpass uses a depth/stencil attachment, pDepthStencilState must be a pointer to a
3268dcfa519862e3ee788cf008388cc6b66832f74477Mark Lobodzinski    // valid structure
3269dcfa519862e3ee788cf008388cc6b66832f74477Mark Lobodzinski    if (pPipeline->graphicsPipelineCI.pRasterizationState &&
3270dcfa519862e3ee788cf008388cc6b66832f74477Mark Lobodzinski        (pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable == VK_FALSE)) {
3271fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes        auto subpass_desc = renderPass ? &renderPass->createInfo.pSubpasses[pPipeline->graphicsPipelineCI.subpass] : nullptr;
32725dcdd90e54199dfeb29938a3a03d998397c22664Chris Forbes        if (subpass_desc && subpass_desc->pDepthStencilAttachment &&
32735dcdd90e54199dfeb29938a3a03d998397c22664Chris Forbes            subpass_desc->pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
32745dcdd90e54199dfeb29938a3a03d998397c22664Chris Forbes            if (!pPipeline->graphicsPipelineCI.pDepthStencilState) {
3275f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
3276f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                                     0, __LINE__, VALIDATION_ERROR_02115, "DS",
32775dcdd90e54199dfeb29938a3a03d998397c22664Chris Forbes                                     "Invalid Pipeline CreateInfo State: "
32785dcdd90e54199dfeb29938a3a03d998397c22664Chris Forbes                                     "pDepthStencilState is NULL when rasterization is enabled and subpass uses a "
3279f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                                     "depth/stencil attachment. %s",
3280f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                                     validation_error_map[VALIDATION_ERROR_02115]);
32815dcdd90e54199dfeb29938a3a03d998397c22664Chris Forbes            }
32825dcdd90e54199dfeb29938a3a03d998397c22664Chris Forbes        }
32835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
328483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
32855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
32865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
32875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Free the Pipeline nodes
32885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic void deletePipelines(layer_data *my_data) {
3289cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (my_data->pipelineMap.size() <= 0) return;
3290ca546210846c65808717f8875deae39bd227c240Tobin Ehlis    for (auto &pipe_map_pair : my_data->pipelineMap) {
3291ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        delete pipe_map_pair.second;
32925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
32935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    my_data->pipelineMap.clear();
32945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
32955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
32965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Block of code at start here specifically for managing/tracking DSs
32975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
32985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Return Pool node ptr for specified pool or else NULL
3299a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin EhlisDESCRIPTOR_POOL_STATE *getDescriptorPoolState(const layer_data *dev_data, const VkDescriptorPool pool) {
3300bb7ea477706f90eb2a72887f652795bc79f60ddeTobin Ehlis    auto pool_it = dev_data->descriptorPoolMap.find(pool);
3301bb7ea477706f90eb2a72887f652795bc79f60ddeTobin Ehlis    if (pool_it == dev_data->descriptorPoolMap.end()) {
33025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return NULL;
33035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
3304bb7ea477706f90eb2a72887f652795bc79f60ddeTobin Ehlis    return pool_it->second;
33055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
33065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3307e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves// Return false if update struct is of valid type, otherwise flag error and return code from callback
3308e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool validUpdateStruct(layer_data *my_data, const VkDevice device, const GENERIC_HEADER *pUpdateStruct) {
33095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (pUpdateStruct->sType) {
3310cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET:
3311cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET:
3312cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return false;
3313cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
3314cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3315cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                           DRAWSTATE_INVALID_UPDATE_STRUCT, "DS",
3316cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                           "Unexpected UPDATE struct of type %s (value %u) in vkUpdateDescriptors() struct tree",
3317cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                           string_VkStructureType(pUpdateStruct->sType), pUpdateStruct->sType);
33185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
33195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
33205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
33215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Set count for given update struct in the last parameter
33225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic uint32_t getUpdateCount(layer_data *my_data, const VkDevice device, const GENERIC_HEADER *pUpdateStruct) {
33235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (pUpdateStruct->sType) {
3324cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET:
3325cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return ((VkWriteDescriptorSet *)pUpdateStruct)->descriptorCount;
3326cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET:
3327cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // TODO : Need to understand this case better and make sure code is correct
3328cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return ((VkCopyDescriptorSet *)pUpdateStruct)->descriptorCount;
3329cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
3330cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return 0;
33315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
33325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
33335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
33345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// For given layout and update, return the first overall index of the layout that is updated
3335fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlisstatic uint32_t getUpdateStartIndex(layer_data *my_data, const VkDevice device, const uint32_t binding_start_index,
33365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                    const uint32_t arrayIndex, const GENERIC_HEADER *pUpdateStruct) {
3337fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis    return binding_start_index + arrayIndex;
33385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
33395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// For given layout and update, return the last overall index of the layout that is updated
3340fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlisstatic uint32_t getUpdateEndIndex(layer_data *my_data, const VkDevice device, const uint32_t binding_start_index,
33415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                  const uint32_t arrayIndex, const GENERIC_HEADER *pUpdateStruct) {
33425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t count = getUpdateCount(my_data, device, pUpdateStruct);
3343fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis    return binding_start_index + arrayIndex + count - 1;
33445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
33455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Verify that the descriptor type in the update struct matches what's expected by the layout
3346fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlisstatic bool validateUpdateConsistency(layer_data *my_data, const VkDevice device, const VkDescriptorType layout_type,
3347e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                                      const GENERIC_HEADER *pUpdateStruct, uint32_t startIndex, uint32_t endIndex) {
33485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // First get actual type of update
334983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
33501d5109d5e0dcc530b27e632e73e1be5e12a28dcdJamie Madill    VkDescriptorType actualType = VK_DESCRIPTOR_TYPE_MAX_ENUM;
33515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (pUpdateStruct->sType) {
3352cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET:
3353cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            actualType = ((VkWriteDescriptorSet *)pUpdateStruct)->descriptorType;
3354cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3355cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET:
3356cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // No need to validate
3357cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return false;
3358cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3359cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
3360cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3361cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 DRAWSTATE_INVALID_UPDATE_STRUCT, "DS",
3362cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "Unexpected UPDATE struct of type %s (value %u) in vkUpdateDescriptors() struct tree",
3363cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 string_VkStructureType(pUpdateStruct->sType), pUpdateStruct->sType);
33645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
336583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (!skip_call) {
3366fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis        if (layout_type != actualType) {
336783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(
3368fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis                my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3369fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis                DRAWSTATE_DESCRIPTOR_TYPE_MISMATCH, "DS",
3370fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis                "Write descriptor update has descriptor type %s that does not match overlapping binding descriptor type of %s!",
3371fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis                string_VkDescriptorType(actualType), string_VkDescriptorType(layout_type));
33725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
33735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
337483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
33755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
3376bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski// TODO: Consolidate functions
3377bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskibool FindLayout(const GLOBAL_CB_NODE *pCB, ImageSubresourcePair imgpair, IMAGE_CMD_BUF_LAYOUT_NODE &node,
3378bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                const VkImageAspectFlags aspectMask) {
33794a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    layer_data *my_data = get_my_data_ptr(get_dispatch_key(pCB->commandBuffer), layer_data_map);
33804a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    if (!(imgpair.subresource.aspectMask & aspectMask)) {
33814a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine        return false;
33824a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    }
33834a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    VkImageAspectFlags oldAspectMask = imgpair.subresource.aspectMask;
33844a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    imgpair.subresource.aspectMask = aspectMask;
33854a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    auto imgsubIt = pCB->imageLayoutMap.find(imgpair);
33864a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    if (imgsubIt == pCB->imageLayoutMap.end()) {
33874a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine        return false;
33884a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    }
33894a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    if (node.layout != VK_IMAGE_LAYOUT_MAX_ENUM && node.layout != imgsubIt->second.layout) {
33904a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine        log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
3391bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                reinterpret_cast<uint64_t &>(imgpair.image), __LINE__, DRAWSTATE_INVALID_LAYOUT, "DS",
33924a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine                "Cannot query for VkImage 0x%" PRIx64 " layout when combined aspect mask %d has multiple layout types: %s and %s",
3393bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                reinterpret_cast<uint64_t &>(imgpair.image), oldAspectMask, string_VkImageLayout(node.layout),
3394bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                string_VkImageLayout(imgsubIt->second.layout));
33954a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    }
33964a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    if (node.initialLayout != VK_IMAGE_LAYOUT_MAX_ENUM && node.initialLayout != imgsubIt->second.initialLayout) {
33974a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine        log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
3398bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                reinterpret_cast<uint64_t &>(imgpair.image), __LINE__, DRAWSTATE_INVALID_LAYOUT, "DS",
3399bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                "Cannot query for VkImage 0x%" PRIx64
3400bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                " layout when combined aspect mask %d has multiple initial layout types: %s and %s",
3401bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                reinterpret_cast<uint64_t &>(imgpair.image), oldAspectMask, string_VkImageLayout(node.initialLayout),
3402bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                string_VkImageLayout(imgsubIt->second.initialLayout));
34034a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    }
34044a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    node = imgsubIt->second;
34054a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    return true;
34064a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine}
34074a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine
3408bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskibool FindLayout(const layer_data *my_data, ImageSubresourcePair imgpair, VkImageLayout &layout,
3409bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                const VkImageAspectFlags aspectMask) {
34104a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    if (!(imgpair.subresource.aspectMask & aspectMask)) {
34114a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine        return false;
34124a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    }
34134a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    VkImageAspectFlags oldAspectMask = imgpair.subresource.aspectMask;
34144a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    imgpair.subresource.aspectMask = aspectMask;
34154a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    auto imgsubIt = my_data->imageLayoutMap.find(imgpair);
34164a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    if (imgsubIt == my_data->imageLayoutMap.end()) {
34174a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine        return false;
34184a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    }
34194a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    if (layout != VK_IMAGE_LAYOUT_MAX_ENUM && layout != imgsubIt->second.layout) {
34204a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine        log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
3421bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                reinterpret_cast<uint64_t &>(imgpair.image), __LINE__, DRAWSTATE_INVALID_LAYOUT, "DS",
34224a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine                "Cannot query for VkImage 0x%" PRIx64 " layout when combined aspect mask %d has multiple layout types: %s and %s",
3423bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                reinterpret_cast<uint64_t &>(imgpair.image), oldAspectMask, string_VkImageLayout(layout),
3424bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                string_VkImageLayout(imgsubIt->second.layout));
34254a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    }
34264a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    layout = imgsubIt->second.layout;
34274a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    return true;
34284a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine}
34294a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine
34305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// find layout(s) on the cmd buf level
34315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisbool FindLayout(const GLOBAL_CB_NODE *pCB, VkImage image, VkImageSubresource range, IMAGE_CMD_BUF_LAYOUT_NODE &node) {
34325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    ImageSubresourcePair imgpair = {image, true, range};
34334a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    node = IMAGE_CMD_BUF_LAYOUT_NODE(VK_IMAGE_LAYOUT_MAX_ENUM, VK_IMAGE_LAYOUT_MAX_ENUM);
34344a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    FindLayout(pCB, imgpair, node, VK_IMAGE_ASPECT_COLOR_BIT);
34354a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    FindLayout(pCB, imgpair, node, VK_IMAGE_ASPECT_DEPTH_BIT);
34364a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    FindLayout(pCB, imgpair, node, VK_IMAGE_ASPECT_STENCIL_BIT);
34374a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    FindLayout(pCB, imgpair, node, VK_IMAGE_ASPECT_METADATA_BIT);
34384a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    if (node.layout == VK_IMAGE_LAYOUT_MAX_ENUM) {
34395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        imgpair = {image, false, VkImageSubresource()};
34404a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine        auto imgsubIt = pCB->imageLayoutMap.find(imgpair);
3441cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (imgsubIt == pCB->imageLayoutMap.end()) return false;
34424a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine        node = imgsubIt->second;
34435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
34445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return true;
34455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
34465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
34475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// find layout(s) on the global level
34485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisbool FindLayout(const layer_data *my_data, ImageSubresourcePair imgpair, VkImageLayout &layout) {
34494a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    layout = VK_IMAGE_LAYOUT_MAX_ENUM;
34504a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    FindLayout(my_data, imgpair, layout, VK_IMAGE_ASPECT_COLOR_BIT);
34514a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    FindLayout(my_data, imgpair, layout, VK_IMAGE_ASPECT_DEPTH_BIT);
34524a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    FindLayout(my_data, imgpair, layout, VK_IMAGE_ASPECT_STENCIL_BIT);
34534a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    FindLayout(my_data, imgpair, layout, VK_IMAGE_ASPECT_METADATA_BIT);
34544a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine    if (layout == VK_IMAGE_LAYOUT_MAX_ENUM) {
34555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        imgpair = {imgpair.image, false, VkImageSubresource()};
34564a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine        auto imgsubIt = my_data->imageLayoutMap.find(imgpair);
3457cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (imgsubIt == my_data->imageLayoutMap.end()) return false;
34584a3279bb23b511257d80ec73ce06d6206d7ab503Michael Lentine        layout = imgsubIt->second.layout;
34595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
34605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return true;
34615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
34625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
34635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisbool FindLayout(const layer_data *my_data, VkImage image, VkImageSubresource range, VkImageLayout &layout) {
34645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    ImageSubresourcePair imgpair = {image, true, range};
34655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return FindLayout(my_data, imgpair, layout);
34665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
34675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
34685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisbool FindLayouts(const layer_data *my_data, VkImage image, std::vector<VkImageLayout> &layouts) {
34695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto sub_data = my_data->imageSubresourceMap.find(image);
3470cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (sub_data == my_data->imageSubresourceMap.end()) return false;
34711facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    auto image_state = getImageState(my_data, image);
3472cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!image_state) return false;
34735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool ignoreGlobal = false;
34745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO: Make this robust for >1 aspect mask. Now it will just say ignore
34755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // potential errors in this case.
34761facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (sub_data->second.size() >= (image_state->createInfo.arrayLayers * image_state->createInfo.mipLevels + 1)) {
34775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        ignoreGlobal = true;
34785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
34795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto imgsubpair : sub_data->second) {
3480cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (ignoreGlobal && !imgsubpair.hasSubresource) continue;
34815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto img_data = my_data->imageLayoutMap.find(imgsubpair);
34825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (img_data != my_data->imageLayoutMap.end()) {
34835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            layouts.push_back(img_data->second.layout);
34845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
34855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
34865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return true;
34875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
34885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
34895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Set the layout on the global level
34905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisvoid SetLayout(layer_data *my_data, ImageSubresourcePair imgpair, const VkImageLayout &layout) {
34915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkImage &image = imgpair.image;
34925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO (mlentine): Maybe set format if new? Not used atm.
34935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    my_data->imageLayoutMap[imgpair].layout = layout;
34945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO (mlentine): Maybe make vector a set?
34955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto subresource = std::find(my_data->imageSubresourceMap[image].begin(), my_data->imageSubresourceMap[image].end(), imgpair);
34965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (subresource == my_data->imageSubresourceMap[image].end()) {
34975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        my_data->imageSubresourceMap[image].push_back(imgpair);
34985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
34995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
35005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
35015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Set the layout on the cmdbuf level
350208682cd3f4809493847b6bdf7605e0a2fede0d56Michael Lentinevoid SetLayout(GLOBAL_CB_NODE *pCB, ImageSubresourcePair imgpair, const IMAGE_CMD_BUF_LAYOUT_NODE &node) {
35035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    pCB->imageLayoutMap[imgpair] = node;
35045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO (mlentine): Maybe make vector a set?
350508682cd3f4809493847b6bdf7605e0a2fede0d56Michael Lentine    auto subresource =
350608682cd3f4809493847b6bdf7605e0a2fede0d56Michael Lentine        std::find(pCB->imageSubresourceMap[imgpair.image].begin(), pCB->imageSubresourceMap[imgpair.image].end(), imgpair);
350708682cd3f4809493847b6bdf7605e0a2fede0d56Michael Lentine    if (subresource == pCB->imageSubresourceMap[imgpair.image].end()) {
350808682cd3f4809493847b6bdf7605e0a2fede0d56Michael Lentine        pCB->imageSubresourceMap[imgpair.image].push_back(imgpair);
35095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
35105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
35115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
351208682cd3f4809493847b6bdf7605e0a2fede0d56Michael Lentinevoid SetLayout(GLOBAL_CB_NODE *pCB, ImageSubresourcePair imgpair, const VkImageLayout &layout) {
35135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO (mlentine): Maybe make vector a set?
351408682cd3f4809493847b6bdf7605e0a2fede0d56Michael Lentine    if (std::find(pCB->imageSubresourceMap[imgpair.image].begin(), pCB->imageSubresourceMap[imgpair.image].end(), imgpair) !=
351508682cd3f4809493847b6bdf7605e0a2fede0d56Michael Lentine        pCB->imageSubresourceMap[imgpair.image].end()) {
35165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->imageLayoutMap[imgpair].layout = layout;
35175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
35185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // TODO (mlentine): Could be expensive and might need to be removed.
35195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        assert(imgpair.hasSubresource);
35205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        IMAGE_CMD_BUF_LAYOUT_NODE node;
35217068a4271b2a542d7e6931104fa62e4a788ed8e5Mark Lobodzinski        if (!FindLayout(pCB, imgpair.image, imgpair.subresource, node)) {
35227068a4271b2a542d7e6931104fa62e4a788ed8e5Mark Lobodzinski            node.initialLayout = layout;
35237068a4271b2a542d7e6931104fa62e4a788ed8e5Mark Lobodzinski        }
352408682cd3f4809493847b6bdf7605e0a2fede0d56Michael Lentine        SetLayout(pCB, imgpair, {node.initialLayout, layout});
35255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
35265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
35275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
352808682cd3f4809493847b6bdf7605e0a2fede0d56Michael Lentinetemplate <class OBJECT, class LAYOUT>
352908682cd3f4809493847b6bdf7605e0a2fede0d56Michael Lentinevoid SetLayout(OBJECT *pObject, ImageSubresourcePair imgpair, const LAYOUT &layout, VkImageAspectFlags aspectMask) {
353008682cd3f4809493847b6bdf7605e0a2fede0d56Michael Lentine    if (imgpair.subresource.aspectMask & aspectMask) {
353108682cd3f4809493847b6bdf7605e0a2fede0d56Michael Lentine        imgpair.subresource.aspectMask = aspectMask;
353208682cd3f4809493847b6bdf7605e0a2fede0d56Michael Lentine        SetLayout(pObject, imgpair, layout);
353308682cd3f4809493847b6bdf7605e0a2fede0d56Michael Lentine    }
35345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
35355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
353608682cd3f4809493847b6bdf7605e0a2fede0d56Michael Lentinetemplate <class OBJECT, class LAYOUT>
353708682cd3f4809493847b6bdf7605e0a2fede0d56Michael Lentinevoid SetLayout(OBJECT *pObject, VkImage image, VkImageSubresource range, const LAYOUT &layout) {
35385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    ImageSubresourcePair imgpair = {image, true, range};
353908682cd3f4809493847b6bdf7605e0a2fede0d56Michael Lentine    SetLayout(pObject, imgpair, layout, VK_IMAGE_ASPECT_COLOR_BIT);
354008682cd3f4809493847b6bdf7605e0a2fede0d56Michael Lentine    SetLayout(pObject, imgpair, layout, VK_IMAGE_ASPECT_DEPTH_BIT);
354108682cd3f4809493847b6bdf7605e0a2fede0d56Michael Lentine    SetLayout(pObject, imgpair, layout, VK_IMAGE_ASPECT_STENCIL_BIT);
354208682cd3f4809493847b6bdf7605e0a2fede0d56Michael Lentine    SetLayout(pObject, imgpair, layout, VK_IMAGE_ASPECT_METADATA_BIT);
35435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
35445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3545cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskitemplate <class OBJECT, class LAYOUT>
3546cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskivoid SetLayout(OBJECT *pObject, VkImage image, const LAYOUT &layout) {
35475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    ImageSubresourcePair imgpair = {image, false, VkImageSubresource()};
354808682cd3f4809493847b6bdf7605e0a2fede0d56Michael Lentine    SetLayout(pObject, image, imgpair, layout);
35495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
35505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
35515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisvoid SetLayout(const layer_data *dev_data, GLOBAL_CB_NODE *pCB, VkImageView imageView, const VkImageLayout &layout) {
355279fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis    auto view_state = getImageViewState(dev_data, imageView);
355379fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis    assert(view_state);
355412d5600c2f9e32343016fd944432ba95df370797Tobin Ehlis    auto image = view_state->create_info.image;
355579fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis    const VkImageSubresourceRange &subRange = view_state->create_info.subresourceRange;
35565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO: Do not iterate over every possibility - consolidate where possible
35575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t j = 0; j < subRange.levelCount; j++) {
35585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t level = subRange.baseMipLevel + j;
35595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t k = 0; k < subRange.layerCount; k++) {
35605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t layer = subRange.baseArrayLayer + k;
35615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            VkImageSubresource sub = {subRange.aspectMask, level, layer};
3562915963fbb05941d3d457f62d6ef61d066b7d73a9Mark Lobodzinski            // TODO: If ImageView was created with depth or stencil, transition both layouts as
3563915963fbb05941d3d457f62d6ef61d066b7d73a9Mark Lobodzinski            // the aspectMask is ignored and both are used. Verify that the extra implicit layout
3564915963fbb05941d3d457f62d6ef61d066b7d73a9Mark Lobodzinski            // is OK for descriptor set layout validation
3565038f931c1696f3e96aeec0e3786b5a47acf908e1Mark Lobodzinski            if (subRange.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
356679fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if (vk_format_is_depth_and_stencil(view_state->create_info.format)) {
3567038f931c1696f3e96aeec0e3786b5a47acf908e1Mark Lobodzinski                    sub.aspectMask |= (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT);
3568038f931c1696f3e96aeec0e3786b5a47acf908e1Mark Lobodzinski                }
3569038f931c1696f3e96aeec0e3786b5a47acf908e1Mark Lobodzinski            }
35705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            SetLayout(pCB, image, sub, layout);
35715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
35725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
35735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
35745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
35755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Validate that given set is valid and that it's not being used by an in-flight CmdBuffer
35765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// func_str is the name of the calling function
3577e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves// Return false if no errors occur
3578e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves// Return true if validation error occurs and callback returns true (to skip upcoming API call down the chain)
35790dcd0f7b37456e2e552d37094ba503c0d089b906Tobin Ehlisstatic bool validateIdleDescriptorSet(const layer_data *dev_data, VkDescriptorSet set, std::string func_str) {
3580cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.idle_descriptor_set) return false;
3581e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
35820dcd0f7b37456e2e552d37094ba503c0d089b906Tobin Ehlis    auto set_node = dev_data->setMap.find(set);
35830dcd0f7b37456e2e552d37094ba503c0d089b906Tobin Ehlis    if (set_node == dev_data->setMap.end()) {
35840dcd0f7b37456e2e552d37094ba503c0d089b906Tobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
35855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                             (uint64_t)(set), __LINE__, DRAWSTATE_DOUBLE_DESTROY, "DS",
3586414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                             "Cannot call %s() on descriptor set 0x%" PRIxLEAST64 " that has not been allocated.", func_str.c_str(),
35875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                             (uint64_t)(set));
35885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
35891c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis        // TODO : This covers various error cases so should pass error enum into this function and use passed in enum here
35905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (set_node->second->in_use.load()) {
35911c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis            skip_call |=
35920dcd0f7b37456e2e552d37094ba503c0d089b906Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
35931c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis                        (uint64_t)(set), __LINE__, VALIDATION_ERROR_00919, "DS",
35941c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis                        "Cannot call %s() on descriptor set 0x%" PRIxLEAST64 " that is in use by a command buffer. %s",
35951c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis                        func_str.c_str(), (uint64_t)(set), validation_error_map[VALIDATION_ERROR_00919]);
35965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
35975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
35985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
35995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
3600f80bf38f4fb3f177b3e1be11b7b1c5edcdbf7d9bChris Forbes
3601e6651096ed8f07840447783c66827cc16d659a49Tobin Ehlis// Remove set from setMap and delete the set
36029dd448578d59cb5ce692e833ba230783b30f3550Tobin Ehlisstatic void freeDescriptorSet(layer_data *dev_data, cvdescriptorset::DescriptorSet *descriptor_set) {
36039dd448578d59cb5ce692e833ba230783b30f3550Tobin Ehlis    dev_data->setMap.erase(descriptor_set->GetSet());
36049dd448578d59cb5ce692e833ba230783b30f3550Tobin Ehlis    delete descriptor_set;
36059dd448578d59cb5ce692e833ba230783b30f3550Tobin Ehlis}
36065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Free all DS Pools including their Sets & related sub-structs
36075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// NOTE : Calls to this function should be wrapped in mutex
36085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic void deletePools(layer_data *my_data) {
3609cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (my_data->descriptorPoolMap.size() <= 0) return;
36105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto ii = my_data->descriptorPoolMap.begin(); ii != my_data->descriptorPoolMap.end(); ++ii) {
3611c5f47f0a54e14c47d402aeabc6498d981ecda9ccTobin Ehlis        // Remove this pools' sets from setMap and delete them
3612cb9ce9e05b8e939d3da35c64997c70049877f4feTobin Ehlis        for (auto ds : (*ii).second->sets) {
36139dd448578d59cb5ce692e833ba230783b30f3550Tobin Ehlis            freeDescriptorSet(my_data, ds);
36145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
3615f13bee0887f3c3d1d597c82869864be3be836737Tobin Ehlis        (*ii).second->sets.clear();
36165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
36175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    my_data->descriptorPoolMap.clear();
36185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
36195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
36205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic void clearDescriptorPool(layer_data *my_data, const VkDevice device, const VkDescriptorPool pool,
36215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                VkDescriptorPoolResetFlags flags) {
3622a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis    DESCRIPTOR_POOL_STATE *pPool = getDescriptorPoolState(my_data, pool);
3623de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    // TODO: validate flags
3624de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    // For every set off of this pool, clear it, remove from setMap, and free cvdescriptorset::DescriptorSet
3625de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    for (auto ds : pPool->sets) {
3626de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis        freeDescriptorSet(my_data, ds);
3627de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    }
3628de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    pPool->sets.clear();
3629de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    // Reset available count for each type and available sets for this pool
3630de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    for (uint32_t i = 0; i < pPool->availableDescriptorTypeCount.size(); ++i) {
3631de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis        pPool->availableDescriptorTypeCount[i] = pPool->maxDescriptorTypeCount[i];
36325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
3633de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    pPool->availableSets = pPool->maxSets;
36345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
36355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
36365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// For given CB object, fetch associated CB Node from map
36375121a8dcacb23766ba4455b4eea429f0a3d62099Chris Forbesstatic GLOBAL_CB_NODE *getCBNode(layer_data const *my_data, const VkCommandBuffer cb) {
36385121a8dcacb23766ba4455b4eea429f0a3d62099Chris Forbes    auto it = my_data->commandBufferMap.find(cb);
36395121a8dcacb23766ba4455b4eea429f0a3d62099Chris Forbes    if (it == my_data->commandBufferMap.end()) {
364072d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis        log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
364172d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                reinterpret_cast<const uint64_t &>(cb), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
3642226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                "Attempt to use CommandBuffer 0x%p that doesn't exist!", cb);
36435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return NULL;
36445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
36455121a8dcacb23766ba4455b4eea429f0a3d62099Chris Forbes    return it->second;
36465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
36475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Free all CB Nodes
36485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// NOTE : Calls to this function should be wrapped in mutex
36495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic void deleteCommandBuffers(layer_data *my_data) {
3650400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis    if (my_data->commandBufferMap.empty()) {
36515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return;
36525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
36535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto ii = my_data->commandBufferMap.begin(); ii != my_data->commandBufferMap.end(); ++ii) {
36545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        delete (*ii).second;
36555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
36565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    my_data->commandBufferMap.clear();
36575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
36585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3659e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool report_error_no_cb_begin(const layer_data *dev_data, const VkCommandBuffer cb, const char *caller_name) {
36605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
36615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                   (uint64_t)cb, __LINE__, DRAWSTATE_NO_BEGIN_COMMAND_BUFFER, "DS",
36625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                   "You must call vkBeginCommandBuffer() before this call to %s", caller_name);
36635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
36645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
366529f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis// If a renderpass is active, verify that the given command type is appropriate for current subpass state
366629f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlisbool ValidateCmdSubpassState(const layer_data *dev_data, const GLOBAL_CB_NODE *pCB, const CMD_TYPE cmd_type) {
3667cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!pCB->activeRenderPass) return false;
3668e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
3669d0d8e333806eaac08bdc87ddeff886dc2b0f09e7Tobin Ehlis    if (pCB->activeSubpassContents == VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS &&
3670d0d8e333806eaac08bdc87ddeff886dc2b0f09e7Tobin Ehlis        (cmd_type != CMD_EXECUTECOMMANDS && cmd_type != CMD_NEXTSUBPASS && cmd_type != CMD_ENDRENDERPASS)) {
36715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
36725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                             DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
36735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                             "Commands cannot be called in a subpass using secondary command buffers.");
36745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else if (pCB->activeSubpassContents == VK_SUBPASS_CONTENTS_INLINE && cmd_type == CMD_EXECUTECOMMANDS) {
36755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
36765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                             DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
36775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                             "vkCmdExecuteCommands() cannot be called in a subpass using inline commands.");
36785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
36795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
36805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
36815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
36825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic bool checkGraphicsBit(const layer_data *my_data, VkQueueFlags flags, const char *name) {
36835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (!(flags & VK_QUEUE_GRAPHICS_BIT))
36845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
36855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                       DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
36865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                       "Cannot call %s on a command buffer allocated from a pool without graphics capabilities.", name);
36875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return false;
36885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
36895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
36905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic bool checkComputeBit(const layer_data *my_data, VkQueueFlags flags, const char *name) {
36915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (!(flags & VK_QUEUE_COMPUTE_BIT))
36925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
36935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                       DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
36945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                       "Cannot call %s on a command buffer allocated from a pool without compute capabilities.", name);
36955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return false;
36965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
36975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
36985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic bool checkGraphicsOrComputeBit(const layer_data *my_data, VkQueueFlags flags, const char *name) {
36995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (!((flags & VK_QUEUE_GRAPHICS_BIT) || (flags & VK_QUEUE_COMPUTE_BIT)))
37005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
37015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                       DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
37025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                       "Cannot call %s on a command buffer allocated from a pool without graphics capabilities.", name);
37035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return false;
37045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
37055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
370629f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis// Validate the given command being added to the specified cmd buffer, flagging errors if CB is not
37075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  in the recording state or if there's an issue with the Cmd ordering
370829f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlisstatic bool ValidateCmd(layer_data *my_data, GLOBAL_CB_NODE *pCB, const CMD_TYPE cmd, const char *caller_name) {
370983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
3710a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes    auto pPool = getCommandPoolNode(my_data, pCB->createInfo.commandPool);
3711a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes    if (pPool) {
3712a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes        VkQueueFlags flags = my_data->phys_dev_properties.queue_family_properties[pPool->queueFamilyIndex].queueFlags;
37135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        switch (cmd) {
3714cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_BINDPIPELINE:
3715cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_BINDPIPELINEDELTA:
3716cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_BINDDESCRIPTORSETS:
3717cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_FILLBUFFER:
3718cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_CLEARCOLORIMAGE:
3719cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_SETEVENT:
3720cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_RESETEVENT:
3721cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_WAITEVENTS:
3722cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_BEGINQUERY:
3723cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_ENDQUERY:
3724cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_RESETQUERYPOOL:
3725cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_COPYQUERYPOOLRESULTS:
3726cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_WRITETIMESTAMP:
3727cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                skip_call |= checkGraphicsOrComputeBit(my_data, flags, cmdTypeToString(cmd).c_str());
3728cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
3729cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_SETVIEWPORTSTATE:
3730cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_SETSCISSORSTATE:
3731cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_SETLINEWIDTHSTATE:
3732cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_SETDEPTHBIASSTATE:
3733cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_SETBLENDSTATE:
3734cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_SETDEPTHBOUNDSSTATE:
3735cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_SETSTENCILREADMASKSTATE:
3736cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_SETSTENCILWRITEMASKSTATE:
3737cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_SETSTENCILREFERENCESTATE:
3738cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_BINDINDEXBUFFER:
3739cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_BINDVERTEXBUFFER:
3740cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_DRAW:
3741cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_DRAWINDEXED:
3742cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_DRAWINDIRECT:
3743cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_DRAWINDEXEDINDIRECT:
3744cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_BLITIMAGE:
3745cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_CLEARATTACHMENTS:
3746cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_CLEARDEPTHSTENCILIMAGE:
3747cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_RESOLVEIMAGE:
3748cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_BEGINRENDERPASS:
3749cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_NEXTSUBPASS:
3750cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_ENDRENDERPASS:
3751cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                skip_call |= checkGraphicsBit(my_data, flags, cmdTypeToString(cmd).c_str());
3752cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
3753cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_DISPATCH:
3754cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_DISPATCHINDIRECT:
3755cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                skip_call |= checkComputeBit(my_data, flags, cmdTypeToString(cmd).c_str());
3756cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
3757cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_COPYBUFFER:
3758cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_COPYIMAGE:
3759cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_COPYBUFFERTOIMAGE:
3760cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_COPYIMAGETOBUFFER:
3761cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_CLONEIMAGEDATA:
3762cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_UPDATEBUFFER:
3763cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_PIPELINEBARRIER:
3764cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_EXECUTECOMMANDS:
3765cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_END:
3766cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
3767cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
3768cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
37695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
37705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
37715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB->state != CB_RECORDING) {
377283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis        skip_call |= report_error_no_cb_begin(my_data, pCB->commandBuffer, caller_name);
37737651c2eb9fe152ba62921ed60454afd882357e2aTobin Ehlis    } else {
377429f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmdSubpassState(my_data, pCB, cmd);
37755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
377683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
37775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
377829f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis
377929f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlisstatic void UpdateCmdBufferLastCmd(layer_data *my_data, GLOBAL_CB_NODE *cb_state, const CMD_TYPE cmd) {
378029f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis    if (cb_state->state == CB_RECORDING) {
378129f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        cb_state->last_cmd = cmd;
378229f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis    }
378329f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis}
37847e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis// For given object struct return a ptr of BASE_NODE type for its wrapping struct
37857e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin EhlisBASE_NODE *GetStateStructPtrFromObject(layer_data *dev_data, VK_OBJECT object_struct) {
37867e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    BASE_NODE *base_ptr = nullptr;
37877e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    switch (object_struct.type) {
3788cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT: {
3789cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            base_ptr = getSetNode(dev_data, reinterpret_cast<VkDescriptorSet &>(object_struct.handle));
3790cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3791cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3792cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT: {
3793cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            base_ptr = getSamplerState(dev_data, reinterpret_cast<VkSampler &>(object_struct.handle));
3794cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3795cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3796cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT: {
3797cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            base_ptr = getQueryPoolNode(dev_data, reinterpret_cast<VkQueryPool &>(object_struct.handle));
3798cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3799cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3800cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT: {
3801cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            base_ptr = getPipelineState(dev_data, reinterpret_cast<VkPipeline &>(object_struct.handle));
3802cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3803cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3804cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT: {
3805cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            base_ptr = getBufferState(dev_data, reinterpret_cast<VkBuffer &>(object_struct.handle));
3806cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3807cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3808cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT: {
3809cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            base_ptr = getBufferViewState(dev_data, reinterpret_cast<VkBufferView &>(object_struct.handle));
3810cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3811cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3812cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT: {
3813cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            base_ptr = getImageState(dev_data, reinterpret_cast<VkImage &>(object_struct.handle));
3814cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3815cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3816cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT: {
3817cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            base_ptr = getImageViewState(dev_data, reinterpret_cast<VkImageView &>(object_struct.handle));
3818cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3819cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3820cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT: {
3821cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            base_ptr = getEventNode(dev_data, reinterpret_cast<VkEvent &>(object_struct.handle));
3822cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3823cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3824cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT: {
3825cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            base_ptr = getDescriptorPoolState(dev_data, reinterpret_cast<VkDescriptorPool &>(object_struct.handle));
3826cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3827cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3828cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT: {
3829cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            base_ptr = getCommandPoolNode(dev_data, reinterpret_cast<VkCommandPool &>(object_struct.handle));
3830cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3831cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3832cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT: {
3833cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            base_ptr = getFramebufferState(dev_data, reinterpret_cast<VkFramebuffer &>(object_struct.handle));
3834cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3835cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3836cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT: {
3837cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            base_ptr = getRenderPassState(dev_data, reinterpret_cast<VkRenderPass &>(object_struct.handle));
3838cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3839cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3840cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT: {
3841cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            base_ptr = getMemObjInfo(dev_data, reinterpret_cast<VkDeviceMemory &>(object_struct.handle));
3842cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3843cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3844cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
3845cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // TODO : Any other objects to be handled here?
3846cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            assert(0);
3847cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3848bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis    }
38497e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    return base_ptr;
38507e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis}
38517e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis
38527e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis// Tie the VK_OBJECT to the cmd buffer which includes:
38537e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis//  Add object_binding to cmd buffer
38547e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis//  Add cb_binding to object
38557e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlisstatic void addCommandBufferBinding(std::unordered_set<GLOBAL_CB_NODE *> *cb_bindings, VK_OBJECT obj, GLOBAL_CB_NODE *cb_node) {
38567e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    cb_bindings->insert(cb_node);
38577e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    cb_node->object_bindings.insert(obj);
38587e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis}
38597e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis// For a given object, if cb_node is in that objects cb_bindings, remove cb_node
38607e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlisstatic void removeCommandBufferBinding(layer_data *dev_data, VK_OBJECT const *object, GLOBAL_CB_NODE *cb_node) {
38617e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    BASE_NODE *base_obj = GetStateStructPtrFromObject(dev_data, *object);
3862cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (base_obj) base_obj->cb_bindings.erase(cb_node);
3863bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis}
38645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Reset the command buffer state
38655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Maintain the createInfo and set state to CB_NEW, but clear all other state
3866400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlisstatic void resetCB(layer_data *dev_data, const VkCommandBuffer cb) {
3867400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis    GLOBAL_CB_NODE *pCB = dev_data->commandBufferMap[cb];
38685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
3869b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine        pCB->in_use.store(0);
3870347d4d3139a1e743ed85bd375c20fd35bbe68d74Chris Forbes        pCB->last_cmd = CMD_NONE;
38715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Reset CB state (note that createInfo is not cleared)
38725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->commandBuffer = cb;
38735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        memset(&pCB->beginInfo, 0, sizeof(VkCommandBufferBeginInfo));
38745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        memset(&pCB->inheritanceInfo, 0, sizeof(VkCommandBufferInheritanceInfo));
38755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->numCmds = 0;
38765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        memset(pCB->drawCount, 0, NUM_DRAW_TYPES * sizeof(uint64_t));
38775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->state = CB_NEW;
38785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->submitCount = 0;
38795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status = 0;
3880b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes        pCB->viewportMask = 0;
3881b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes        pCB->scissorMask = 0;
388293c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski
388372d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis        for (uint32_t i = 0; i < VK_PIPELINE_BIND_POINT_RANGE_SIZE; ++i) {
388472d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis            pCB->lastBound[i].reset();
388572d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis        }
388693c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski
38875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        memset(&pCB->activeRenderPassBeginInfo, 0, sizeof(pCB->activeRenderPassBeginInfo));
3888ee691f5c5fa87aac3750454d2bca2cb582e4e817Chris Forbes        pCB->activeRenderPass = nullptr;
38895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->activeSubpassContents = VK_SUBPASS_CONTENTS_INLINE;
38905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->activeSubpass = 0;
3891e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis        pCB->broken_bindings.clear();
38925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->waitedEvents.clear();
38935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->events.clear();
3894c7e6bc41aa9c6e5a677b138b9459b252cd3bedf2Mark Lobodzinski        pCB->writeEventsBeforeWait.clear();
38955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->waitedEventsBeforeQueryReset.clear();
38965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->queryToStateMap.clear();
38975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->activeQueries.clear();
38985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->startedQueries.clear();
3899abfafae4ec5d76e520916b03d196e474e972c949Michael Lentine        pCB->imageSubresourceMap.clear();
39005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->imageLayoutMap.clear();
39015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->eventToStageMap.clear();
39025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->drawData.clear();
39035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->currentDrawData.buffers.clear();
390458b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis        pCB->vertex_buffer_used = false;
39055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->primaryCommandBuffer = VK_NULL_HANDLE;
3906bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        // Make sure any secondaryCommandBuffers are removed from globalInFlight
3907bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        for (auto secondary_cb : pCB->secondaryCommandBuffers) {
3908bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis            dev_data->globalInFlightCmdBuffers.erase(secondary_cb);
3909bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        }
39105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->secondaryCommandBuffers.clear();
39117a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        pCB->updateImages.clear();
39127a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        pCB->updateBuffers.clear();
3913400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis        clear_cmd_buf_and_mem_references(dev_data, pCB);
3914b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        pCB->eventUpdates.clear();
3915d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        pCB->queryUpdates.clear();
391693c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski
3917bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis        // Remove object bindings
3918bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis        for (auto obj : pCB->object_bindings) {
3919bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis            removeCommandBufferBinding(dev_data, &obj, pCB);
3920bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis        }
3921a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis        pCB->object_bindings.clear();
392293c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski        // Remove this cmdBuffer's reference from each FrameBuffer's CB ref list
392393c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski        for (auto framebuffer : pCB->framebuffers) {
3924c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis            auto fb_state = getFramebufferState(dev_data, framebuffer);
3925cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (fb_state) fb_state->cb_bindings.erase(pCB);
392693c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski        }
392793c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski        pCB->framebuffers.clear();
39287003b38da5cc27a063af3c45080f3a35438283eeTobin Ehlis        pCB->activeFramebuffer = VK_NULL_HANDLE;
39295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
39305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
39315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
39325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Set PSO-related status bits for CB, including dynamic state set via PSO
39334c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic void set_cb_pso_status(GLOBAL_CB_NODE *pCB, const PIPELINE_STATE *pPipe) {
39345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Account for any dynamic state not set via this PSO
3935ca546210846c65808717f8875deae39bd227c240Tobin Ehlis    if (!pPipe->graphicsPipelineCI.pDynamicState ||
3936cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        !pPipe->graphicsPipelineCI.pDynamicState->dynamicStateCount) {  // All state is static
39374052946ae557337ff95f3725e879131b1c63f865Tobin Ehlis        pCB->status |= CBSTATUS_ALL_STATE_SET;
39385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
39395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // First consider all state on
39405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Then unset any state that's noted as dynamic in PSO
39415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Finally OR that into CB statemask
39424052946ae557337ff95f3725e879131b1c63f865Tobin Ehlis        CBStatusFlags psoDynStateMask = CBSTATUS_ALL_STATE_SET;
3943ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        for (uint32_t i = 0; i < pPipe->graphicsPipelineCI.pDynamicState->dynamicStateCount; i++) {
3944ca546210846c65808717f8875deae39bd227c240Tobin Ehlis            switch (pPipe->graphicsPipelineCI.pDynamicState->pDynamicStates[i]) {
3945cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_LINE_WIDTH:
3946cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_LINE_WIDTH_SET;
3947cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3948cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_DEPTH_BIAS:
3949cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_DEPTH_BIAS_SET;
3950cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3951cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_BLEND_CONSTANTS:
3952cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_BLEND_CONSTANTS_SET;
3953cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3954cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_DEPTH_BOUNDS:
3955cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_DEPTH_BOUNDS_SET;
3956cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3957cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK:
3958cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_STENCIL_READ_MASK_SET;
3959cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3960cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_STENCIL_WRITE_MASK:
3961cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_STENCIL_WRITE_MASK_SET;
3962cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3963cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_STENCIL_REFERENCE:
3964cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_STENCIL_REFERENCE_SET;
3965cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3966cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                default:
3967cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    // TODO : Flag error here
3968cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
39695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
39705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
39715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= psoDynStateMask;
39725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
39735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
39745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
39755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Flags validation error if the associated call is made inside a render pass. The apiName
39765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// routine should ONLY be called outside a render pass.
3977ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblenstatic bool insideRenderPass(const layer_data *my_data, GLOBAL_CB_NODE *pCB, const char *apiName,
3978ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                             UNIQUE_VALIDATION_ERROR_CODE msgCode) {
3979e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool inside = false;
39805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB->activeRenderPass) {
39815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        inside = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3982ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                         (uint64_t)pCB->commandBuffer, __LINE__, msgCode, "DS",
3983ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                         "%s: It is invalid to issue this call inside an active render pass (0x%" PRIxLEAST64 "). %s", apiName,
3984ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                         (uint64_t)pCB->activeRenderPass->renderPass, validation_error_map[msgCode]);
39855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
39865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return inside;
39875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
39885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
39895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Flags validation error if the associated call is made outside a render pass. The apiName
39905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// routine should ONLY be called inside a render pass.
3991ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblenstatic bool outsideRenderPass(const layer_data *my_data, GLOBAL_CB_NODE *pCB, const char *apiName,
3992ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                              UNIQUE_VALIDATION_ERROR_CODE msgCode) {
3993e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool outside = false;
39945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (((pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_PRIMARY) && (!pCB->activeRenderPass)) ||
39955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        ((pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY) && (!pCB->activeRenderPass) &&
39965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis         !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT))) {
39975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        outside = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3998ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                          (uint64_t)pCB->commandBuffer, __LINE__, msgCode, "DS",
3999ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                          "%s: This call must be issued inside an active render pass. %s", apiName, validation_error_map[msgCode]);
40005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
40015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return outside;
40025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
40035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4004f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbesstatic void init_core_validation(instance_layer_data *instance_data, const VkAllocationCallbacks *pAllocator) {
4005b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis    layer_debug_actions(instance_data->report_data, instance_data->logging_callback, pAllocator, "lunarg_core_validation");
40065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
40075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4008747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbesstatic void checkInstanceRegisterExtensions(const VkInstanceCreateInfo *pCreateInfo, instance_layer_data *instance_data) {
4009747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
4010747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_SURFACE_EXTENSION_NAME))
4011747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->surfaceExtensionEnabled = true;
4012747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_DISPLAY_EXTENSION_NAME))
4013747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->displayExtensionEnabled = true;
4014747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_ANDROID_KHR
4015747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_ANDROID_SURFACE_EXTENSION_NAME))
4016747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->androidSurfaceExtensionEnabled = true;
4017747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#endif
4018747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_MIR_KHR
4019747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_MIR_SURFACE_EXTENSION_NAME))
4020747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->mirSurfaceExtensionEnabled = true;
4021747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#endif
4022747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WAYLAND_KHR
4023747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME))
4024747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->waylandSurfaceExtensionEnabled = true;
4025747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#endif
4026747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WIN32_KHR
4027747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_WIN32_SURFACE_EXTENSION_NAME))
4028747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->win32SurfaceExtensionEnabled = true;
4029747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#endif
4030747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XCB_KHR
4031747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_XCB_SURFACE_EXTENSION_NAME))
4032747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->xcbSurfaceExtensionEnabled = true;
4033747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#endif
4034747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XLIB_KHR
4035747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_XLIB_SURFACE_EXTENSION_NAME))
4036747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->xlibSurfaceExtensionEnabled = true;
4037747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#endif
4038747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
4039747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
4040747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
4041bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
4042bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              VkInstance *pInstance) {
40435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkLayerInstanceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
40445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
40455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(chain_info->u.pLayerInfo);
40465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
40475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance");
4048cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (fpCreateInstance == NULL) return VK_ERROR_INITIALIZATION_FAILED;
40495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
40505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Advance the link info for the next element on the chain
40515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
40525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
40535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
4054cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (result != VK_SUCCESS) return result;
40555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4056f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes    instance_layer_data *instance_data = get_my_data_ptr(get_dispatch_key(*pInstance), instance_layer_data_map);
405756a5ba3e60a723781945959ffc10e2e215350de5Chia-I Wu    instance_data->instance = *pInstance;
40589172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    layer_init_instance_dispatch_table(*pInstance, &instance_data->dispatch_table, fpGetInstanceProcAddr);
40599172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    instance_data->report_data = debug_report_create_instance(
40609172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes        &instance_data->dispatch_table, *pInstance, pCreateInfo->enabledExtensionCount, pCreateInfo->ppEnabledExtensionNames);
4061747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    checkInstanceRegisterExtensions(pCreateInfo, instance_data);
4062b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis    init_core_validation(instance_data, pAllocator);
4063825ac70f99460ccb9494d34f93d8ee7ec303e5deMark Lobodzinski
40645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    ValidateLayerOrdering(*pCreateInfo);
40655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
40665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
40675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
40685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
406925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// Hook DestroyInstance to remove tableInstanceMap entry
407089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL DestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
40715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODOSC : Shouldn't need any customization here
40725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dispatch_key key = get_dispatch_key(instance);
40735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TBD: Need any locking this early, in case this function is called at the
40745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // same time by more than one thread?
40759172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    instance_layer_data *instance_data = get_my_data_ptr(key, instance_layer_data_map);
40769172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    instance_data->dispatch_table.DestroyInstance(instance, pAllocator);
40775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4078b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::lock_guard<std::mutex> lock(global_lock);
40795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Clean up logging callback, if any
40809172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    while (instance_data->logging_callback.size() > 0) {
40819172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes        VkDebugReportCallbackEXT callback = instance_data->logging_callback.back();
40829172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes        layer_destroy_msg_callback(instance_data->report_data, callback, pAllocator);
40839172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes        instance_data->logging_callback.pop_back();
40845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
40855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
40869172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    layer_debug_report_destroy_instance(instance_data->report_data);
40875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data_map.erase(key);
40885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
40895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4090373469f006399d6b5204ee05db3b56beb168b36fMark Youngstatic void checkDeviceRegisterExtensions(const VkDeviceCreateInfo *pCreateInfo, VkDevice device) {
40915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t i;
40925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TBD: Need any locking, in case this function is called at the same time
40935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // by more than one thread?
40945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
40955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->device_extensions.wsi_enabled = false;
4096c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young    dev_data->device_extensions.wsi_display_swapchain_enabled = false;
40975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
40985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
40995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0)
41005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->device_extensions.wsi_enabled = true;
4101c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME) == 0)
4102c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young            dev_data->device_extensions.wsi_display_swapchain_enabled = true;
41035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
41045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
41055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4106838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski// Verify that queue family has been properly requested
4107ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblenstatic bool ValidateRequestedQueueFamilyProperties(instance_layer_data *instance_data, VkPhysicalDevice gpu,
4108ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                                                   const VkDeviceCreateInfo *create_info) {
4109838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski    bool skip_call = false;
41104b293996aa6a9bd92ef1f0175eca4b0e8a9fd9fcChris Forbes    auto physical_device_state = getPhysicalDeviceState(instance_data, gpu);
4111838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski    // First check is app has actually requested queueFamilyProperties
41124b293996aa6a9bd92ef1f0175eca4b0e8a9fd9fcChris Forbes    if (!physical_device_state) {
4113bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        skip_call |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
4114bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVLIMITS_MUST_QUERY_COUNT, "DL",
4115838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski                             "Invalid call to vkCreateDevice() w/o first calling vkEnumeratePhysicalDevices().");
41164b293996aa6a9bd92ef1f0175eca4b0e8a9fd9fcChris Forbes    } else if (QUERY_DETAILS != physical_device_state->vkGetPhysicalDeviceQueueFamilyPropertiesState) {
4117838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski        // TODO: This is not called out as an invalid use in the spec so make more informative recommendation.
41184b293996aa6a9bd92ef1f0175eca4b0e8a9fd9fcChris Forbes        skip_call |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
4119838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski                             VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVLIMITS_INVALID_QUEUE_CREATE_REQUEST,
4120838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski                             "DL", "Call to vkCreateDevice() w/o first calling vkGetPhysicalDeviceQueueFamilyProperties().");
4121838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski    } else {
4122838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski        // Check that the requested queue properties are valid
4123838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski        for (uint32_t i = 0; i < create_info->queueCreateInfoCount; i++) {
4124838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski            uint32_t requestedIndex = create_info->pQueueCreateInfos[i].queueFamilyIndex;
41257d8b6ab1b68c397da50bad43deb1fba389ebace7Chris Forbes            if (requestedIndex >= physical_device_state->queue_family_properties.size()) {
4126838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski                skip_call |= log_msg(
41274b293996aa6a9bd92ef1f0175eca4b0e8a9fd9fcChris Forbes                    instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0,
4128838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski                    __LINE__, DEVLIMITS_INVALID_QUEUE_CREATE_REQUEST, "DL",
4129838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski                    "Invalid queue create request in vkCreateDevice(). Invalid queueFamilyIndex %u requested.", requestedIndex);
4130838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski            } else if (create_info->pQueueCreateInfos[i].queueCount >
41317d8b6ab1b68c397da50bad43deb1fba389ebace7Chris Forbes                       physical_device_state->queue_family_properties[requestedIndex].queueCount) {
4132cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                skip_call |= log_msg(
4133cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0,
4134cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    __LINE__, DEVLIMITS_INVALID_QUEUE_CREATE_REQUEST, "DL",
4135cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "Invalid queue create request in vkCreateDevice(). QueueFamilyIndex %u only has %u queues, but "
4136cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "requested queueCount is %u.",
4137cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    requestedIndex, physical_device_state->queue_family_properties[requestedIndex].queueCount,
4138cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    create_info->pQueueCreateInfos[i].queueCount);
4139838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski            }
4140838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski        }
4141838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski    }
4142838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski    return skip_call;
4143838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski}
4144838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski
4145f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski// Verify that features have been queried and that they are available
4146bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool ValidateRequestedFeatures(instance_layer_data *dev_data, VkPhysicalDevice phys,
4147bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                      const VkPhysicalDeviceFeatures *requested_features) {
4148f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    bool skip_call = false;
4149f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
41503bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes    auto phys_device_state = getPhysicalDeviceState(dev_data, phys);
41513bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes    const VkBool32 *actual = reinterpret_cast<VkBool32 *>(&phys_device_state->features);
4152825ac70f99460ccb9494d34f93d8ee7ec303e5deMark Lobodzinski    const VkBool32 *requested = reinterpret_cast<const VkBool32 *>(requested_features);
4153f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    // TODO : This is a nice, compact way to loop through struct, but a bad way to report issues
4154f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    //  Need to provide the struct member name with the issue. To do that seems like we'll
4155f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    //  have to loop through each struct member which should be done w/ codegen to keep in synch.
4156f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    uint32_t errors = 0;
4157f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    uint32_t total_bools = sizeof(VkPhysicalDeviceFeatures) / sizeof(VkBool32);
4158f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    for (uint32_t i = 0; i < total_bools; i++) {
4159f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski        if (requested[i] > actual[i]) {
4160f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski            // TODO: Add index to struct member name helper to be able to include a feature name
4161cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            skip_call |=
4162cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0,
4163cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        __LINE__, DEVLIMITS_INVALID_FEATURE_REQUESTED, "DL",
4164cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "While calling vkCreateDevice(), requesting feature #%u in VkPhysicalDeviceFeatures struct, "
4165cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "which is not available on this device.",
4166cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        i);
4167f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski            errors++;
4168f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski        }
4169f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    }
41703bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes    if (errors && (UNCALLED == phys_device_state->vkGetPhysicalDeviceFeaturesState)) {
4171f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski        // If user didn't request features, notify them that they should
4172f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski        // TODO: Verify this against the spec. I believe this is an invalid use of the API and should return an error
4173bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
4174bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             0, __LINE__, DEVLIMITS_INVALID_FEATURE_REQUESTED, "DL",
4175bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             "You requested features that are unavailable on this device. You should first query feature "
4176bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             "availability by calling vkGetPhysicalDeviceFeatures().");
4177f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    }
4178f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    return skip_call;
4179f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski}
4180f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
418189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo,
418289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                            const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
4183f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes    instance_layer_data *my_instance_data = get_my_data_ptr(get_dispatch_key(gpu), instance_layer_data_map);
4184f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    bool skip_call = false;
4185f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
4186f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    // Check that any requested features are available
4187f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    if (pCreateInfo->pEnabledFeatures) {
41883bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes        skip_call |= ValidateRequestedFeatures(my_instance_data, gpu, pCreateInfo->pEnabledFeatures);
4189f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    }
41904b293996aa6a9bd92ef1f0175eca4b0e8a9fd9fcChris Forbes    skip_call |= ValidateRequestedQueueFamilyProperties(my_instance_data, gpu, pCreateInfo);
4191f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
41921d659b4113b77a95325df10d602a03f1e7abf8b7Mark Mueller    if (skip_call) {
41931d659b4113b77a95325df10d602a03f1e7abf8b7Mark Mueller        return VK_ERROR_VALIDATION_FAILED_EXT;
41941d659b4113b77a95325df10d602a03f1e7abf8b7Mark Mueller    }
41951d659b4113b77a95325df10d602a03f1e7abf8b7Mark Mueller
41965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkLayerDeviceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
41975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
41985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(chain_info->u.pLayerInfo);
41995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
42005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;
420156a5ba3e60a723781945959ffc10e2e215350de5Chia-I Wu    PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(my_instance_data->instance, "vkCreateDevice");
42025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (fpCreateDevice == NULL) {
42035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return VK_ERROR_INITIALIZATION_FAILED;
42045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
42055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
42065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Advance the link info for the next element on the chain
42075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
42085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
42095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = fpCreateDevice(gpu, pCreateInfo, pAllocator, pDevice);
42105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result != VK_SUCCESS) {
42115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return result;
42125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
42135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4214b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
42155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *my_device_data = get_my_data_ptr(get_dispatch_key(*pDevice), layer_data_map);
42165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
421707a464bd7fec9583f346b8c4b8d43c88d2e9ffa4Chris Forbes    my_device_data->instance_data = my_instance_data;
42185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Setup device dispatch table
42194a0754042cf090e131e9e769d8a3633c228625beChris Forbes    layer_init_device_dispatch_table(*pDevice, &my_device_data->dispatch_table, fpGetDeviceProcAddr);
42206c94fb996af5f7f79a2bff04cc8cf425086de111Chris Forbes    my_device_data->device = *pDevice;
4221ec85232c4d8d9ddf7d2ae57cb8203c5ab52c1106Mark Lobodzinski    // Save PhysicalDevice handle
4222ec85232c4d8d9ddf7d2ae57cb8203c5ab52c1106Mark Lobodzinski    my_device_data->physical_device = gpu;
42235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
42245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    my_device_data->report_data = layer_debug_report_create_device(my_instance_data->report_data, *pDevice);
4225373469f006399d6b5204ee05db3b56beb168b36fMark Young    checkDeviceRegisterExtensions(pCreateInfo, *pDevice);
42265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Get physical device limits for this device
42279172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    my_instance_data->dispatch_table.GetPhysicalDeviceProperties(gpu, &(my_device_data->phys_dev_properties.properties));
42285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t count;
42299172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    my_instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties(gpu, &count, nullptr);
4230b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis    my_device_data->phys_dev_properties.queue_family_properties.resize(count);
42319172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    my_instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties(
4232b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis        gpu, &count, &my_device_data->phys_dev_properties.queue_family_properties[0]);
42335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO: device limits should make sure these are compatible
42345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCreateInfo->pEnabledFeatures) {
4235f71dd305f197826a61f398bff725267a20ea1d90Chris Forbes        my_device_data->enabled_features = *pCreateInfo->pEnabledFeatures;
42365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
4237f71dd305f197826a61f398bff725267a20ea1d90Chris Forbes        memset(&my_device_data->enabled_features, 0, sizeof(VkPhysicalDeviceFeatures));
42385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
4239e47dbc3f3340fa177d877a67b2adb76a570027e5Mark Lobodzinski    // Store physical device properties and physical device mem limits into device layer_data structs
42409172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    my_instance_data->dispatch_table.GetPhysicalDeviceMemoryProperties(gpu, &my_device_data->phys_dev_mem_props);
4241e47dbc3f3340fa177d877a67b2adb76a570027e5Mark Lobodzinski    my_instance_data->dispatch_table.GetPhysicalDeviceProperties(gpu, &my_device_data->phys_dev_props);
4242b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
42435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
42445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    ValidateLayerOrdering(*pCreateInfo);
42455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
42465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
42475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
42485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
42495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// prototype
425089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL DestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) {
42515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODOSC : Shouldn't need any customization here
42523ec39aeb6d6f08fb1ee45f64f72543a710754c62Tobin Ehlis    bool skip = false;
42535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dispatch_key key = get_dispatch_key(device);
42545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(key, layer_data_map);
42555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Free all the memory
4256b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
42575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    deletePipelines(dev_data);
4258fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    dev_data->renderPassMap.clear();
42595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    deleteCommandBuffers(dev_data);
4260f13bee0887f3c3d1d597c82869864be3be836737Tobin Ehlis    // This will also delete all sets in the pool & remove them from setMap
42615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    deletePools(dev_data);
4262f13bee0887f3c3d1d597c82869864be3be836737Tobin Ehlis    // All sets should be removed
4263f13bee0887f3c3d1d597c82869864be3be836737Tobin Ehlis    assert(dev_data->setMap.empty());
4264a1e5173c89eb7f03e0434ad45ccd1471e722fa71Tobin Ehlis    for (auto del_layout : dev_data->descriptorSetLayoutMap) {
4265a1e5173c89eb7f03e0434ad45ccd1471e722fa71Tobin Ehlis        delete del_layout.second;
4266a1e5173c89eb7f03e0434ad45ccd1471e722fa71Tobin Ehlis    }
4267fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis    dev_data->descriptorSetLayoutMap.clear();
42685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->imageViewMap.clear();
42695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->imageMap.clear();
42705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->imageSubresourceMap.clear();
42715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->imageLayoutMap.clear();
42725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->bufferViewMap.clear();
42735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->bufferMap.clear();
42741344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis    // Queues persist until device is destroyed
42751344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis    dev_data->queueMap.clear();
42765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Report any memory leaks
42775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_debug_report_destroy_device(device);
4278b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
42795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
42805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#if DISPATCH_MAP_DEBUG
4281414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller    fprintf(stderr, "Device: 0x%p, key: 0x%p\n", device, key);
42825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#endif
42833ec39aeb6d6f08fb1ee45f64f72543a710754c62Tobin Ehlis    if (!skip) {
42844a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyDevice(device, pAllocator);
42853ec39aeb6d6f08fb1ee45f64f72543a710754c62Tobin Ehlis        layer_data_map.erase(key);
42865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
42875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
42885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
42895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic const VkExtensionProperties instance_extensions[] = {{VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION}};
42905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4291208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis// For given stage mask, if Geometry shader stage is on w/o GS being enabled, report geo_error_id
4292208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis//   and if Tessellation Control or Evaluation shader stages are on w/o TS being enabled, report tess_error_id
4293208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlisstatic bool ValidateStageMaskGsTsEnables(layer_data *dev_data, VkPipelineStageFlags stageMask, const char *caller,
4294208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                                         UNIQUE_VALIDATION_ERROR_CODE geo_error_id, UNIQUE_VALIDATION_ERROR_CODE tess_error_id) {
4295208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    bool skip = false;
4296208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    if (!dev_data->enabled_features.geometryShader && (stageMask & VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT)) {
4297208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
4298cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        geo_error_id, "DL",
4299cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "%s call includes a stageMask with VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT bit set when "
4300cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "device does not have geometryShader feature enabled. %s",
4301208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                        caller, validation_error_map[geo_error_id]);
4302208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    }
4303208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    if (!dev_data->enabled_features.tessellationShader &&
4304208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        (stageMask & (VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT | VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT))) {
4305208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
4306cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        tess_error_id, "DL",
4307cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "%s call includes a stageMask with VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT "
4308cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "and/or VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT bit(s) set when device "
4309cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "does not have tessellationShader feature enabled. %s",
4310208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                        caller, validation_error_map[tess_error_id]);
4311208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    }
4312208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    return skip;
4313208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis}
4314208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis
43155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// This validates that the initial layout specified in the command buffer for
43165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// the IMAGE is the same
43175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// as the global IMAGE layout
4318971020aec6166f20a12a833ebd003e0193f4160aChris Forbesstatic bool ValidateCmdBufImageLayouts(layer_data *dev_data, GLOBAL_CB_NODE *pCB) {
4319e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
43205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto cb_image_data : pCB->imageLayoutMap) {
43215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        VkImageLayout imageLayout;
43225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!FindLayout(dev_data, cb_image_data.first, imageLayout)) {
4323bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
4324bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
4325bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 "Cannot submit cmd buffer using deleted image 0x%" PRIx64 ".",
4326bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 reinterpret_cast<const uint64_t &>(cb_image_data.first));
43275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
43285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (cb_image_data.second.initialLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
43295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // TODO: Set memory invalid which is in mem_tracker currently
43305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else if (imageLayout != cb_image_data.second.initialLayout) {
4331856ecb404bc959ddb877c150c9caa0649055b9cbMark Young                if (cb_image_data.first.hasSubresource) {
4332856ecb404bc959ddb877c150c9caa0649055b9cbMark Young                    skip_call |= log_msg(
4333856ecb404bc959ddb877c150c9caa0649055b9cbMark Young                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
4334971020aec6166f20a12a833ebd003e0193f4160aChris Forbes                        reinterpret_cast<uint64_t &>(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
4335bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        "Cannot submit cmd buffer using image (0x%" PRIx64
4336bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        ") [sub-resource: aspectMask 0x%X array layer %u, mip level %u], "
4337856ecb404bc959ddb877c150c9caa0649055b9cbMark Young                        "with layout %s when first use is %s.",
4338414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                        reinterpret_cast<const uint64_t &>(cb_image_data.first.image), cb_image_data.first.subresource.aspectMask,
4339bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        cb_image_data.first.subresource.arrayLayer, cb_image_data.first.subresource.mipLevel,
4340bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        string_VkImageLayout(imageLayout), string_VkImageLayout(cb_image_data.second.initialLayout));
4341856ecb404bc959ddb877c150c9caa0649055b9cbMark Young                } else {
4342cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip_call |=
4343cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
4344cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t &>(pCB->commandBuffer),
4345cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Cannot submit cmd buffer using image (0x%" PRIx64
4346cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                                                ") with layout %s when "
4347cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                                                "first use is %s.",
4348cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                reinterpret_cast<const uint64_t &>(cb_image_data.first.image), string_VkImageLayout(imageLayout),
4349cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                string_VkImageLayout(cb_image_data.second.initialLayout));
4350856ecb404bc959ddb877c150c9caa0649055b9cbMark Young                }
43515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
43525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            SetLayout(dev_data, cb_image_data.first, cb_image_data.second.layout);
43535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
43545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
43555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
43565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
435739d153555b5101b1b093d80100e329368c66b79dMark Lobodzinski
4358a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis// Loop through bound objects and increment their in_use counts
4359a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis//  For any unknown objects, flag an error
43602f8cbf3b166e175174877a59929902e005953d6dTobin Ehlisstatic bool ValidateAndIncrementBoundObjects(layer_data *dev_data, GLOBAL_CB_NODE const *cb_node) {
4361162dac96d3883e8fffaa1f988043f62c06662d2eTobin Ehlis    bool skip = false;
4362162dac96d3883e8fffaa1f988043f62c06662d2eTobin Ehlis    DRAW_STATE_ERROR error_code = DRAWSTATE_NONE;
4363162dac96d3883e8fffaa1f988043f62c06662d2eTobin Ehlis    BASE_NODE *base_obj = nullptr;
4364a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    for (auto obj : cb_node->object_bindings) {
4365a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis        switch (obj.type) {
4366cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT: {
4367cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                base_obj = getSetNode(dev_data, reinterpret_cast<VkDescriptorSet &>(obj.handle));
4368cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_DESCRIPTOR_SET;
4369cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4370cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4371cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT: {
4372cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                base_obj = getSamplerState(dev_data, reinterpret_cast<VkSampler &>(obj.handle));
4373cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_SAMPLER;
4374cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4375cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4376cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT: {
4377cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                base_obj = getQueryPoolNode(dev_data, reinterpret_cast<VkQueryPool &>(obj.handle));
4378cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_QUERY_POOL;
4379cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4380cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4381cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT: {
4382cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                base_obj = getPipelineState(dev_data, reinterpret_cast<VkPipeline &>(obj.handle));
4383cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_PIPELINE;
4384cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4385cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4386cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT: {
4387cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                base_obj = getBufferState(dev_data, reinterpret_cast<VkBuffer &>(obj.handle));
4388cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_BUFFER;
4389cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4390cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4391cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT: {
4392cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                base_obj = getBufferViewState(dev_data, reinterpret_cast<VkBufferView &>(obj.handle));
4393cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_BUFFER_VIEW;
4394cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4395cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4396cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT: {
4397cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                base_obj = getImageState(dev_data, reinterpret_cast<VkImage &>(obj.handle));
4398cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_IMAGE;
4399cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4400cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4401cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT: {
4402cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                base_obj = getImageViewState(dev_data, reinterpret_cast<VkImageView &>(obj.handle));
4403cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_IMAGE_VIEW;
4404cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4405cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4406cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT: {
4407cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                base_obj = getEventNode(dev_data, reinterpret_cast<VkEvent &>(obj.handle));
4408cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_EVENT;
4409cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4410cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4411cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT: {
4412cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                base_obj = getDescriptorPoolState(dev_data, reinterpret_cast<VkDescriptorPool &>(obj.handle));
4413cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_DESCRIPTOR_POOL;
4414cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4415cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4416cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT: {
4417cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                base_obj = getCommandPoolNode(dev_data, reinterpret_cast<VkCommandPool &>(obj.handle));
4418cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_COMMAND_POOL;
4419cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4420cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4421cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT: {
4422cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                base_obj = getFramebufferState(dev_data, reinterpret_cast<VkFramebuffer &>(obj.handle));
4423cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_FRAMEBUFFER;
4424cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4425cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4426cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT: {
4427cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                base_obj = getRenderPassState(dev_data, reinterpret_cast<VkRenderPass &>(obj.handle));
4428cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_RENDERPASS;
4429cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4430cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4431cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT: {
4432cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                base_obj = getMemObjInfo(dev_data, reinterpret_cast<VkDeviceMemory &>(obj.handle));
4433cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_DEVICE_MEMORY;
4434cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4435cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4436cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
4437cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // TODO : Merge handling of other objects types into this code
4438cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4439a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis        }
4440162dac96d3883e8fffaa1f988043f62c06662d2eTobin Ehlis        if (!base_obj) {
4441162dac96d3883e8fffaa1f988043f62c06662d2eTobin Ehlis            skip |=
4442162dac96d3883e8fffaa1f988043f62c06662d2eTobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, obj.type, obj.handle, __LINE__, error_code, "DS",
4443162dac96d3883e8fffaa1f988043f62c06662d2eTobin Ehlis                        "Cannot submit cmd buffer using deleted %s 0x%" PRIx64 ".", object_type_to_string(obj.type), obj.handle);
4444162dac96d3883e8fffaa1f988043f62c06662d2eTobin Ehlis        } else {
4445162dac96d3883e8fffaa1f988043f62c06662d2eTobin Ehlis            base_obj->in_use.fetch_add(1);
4446162dac96d3883e8fffaa1f988043f62c06662d2eTobin Ehlis        }
4447a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    }
4448162dac96d3883e8fffaa1f988043f62c06662d2eTobin Ehlis    return skip;
4449a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis}
4450a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis
44515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Track which resources are in-flight by atomically incrementing their "in_use" count
44529a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlisstatic bool validateAndIncrementResources(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
4453e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
4454a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
44559a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis    cb_node->in_use.fetch_add(1);
44569a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis    dev_data->globalInFlightCmdBuffers.insert(cb_node->commandBuffer);
4457a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
4458a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    // First Increment for all "generic" objects bound to cmd buffer, followed by special-case objects below
44599a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis    skip_call |= ValidateAndIncrementBoundObjects(dev_data, cb_node);
4460a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    // TODO : We should be able to remove the NULL look-up checks from the code below as long as
4461a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    //  all the corresponding cases are verified to cause CB_INVALID state and the CB_INVALID state
4462a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    //  should then be flagged prior to calling this function
44639a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis    for (auto drawDataElement : cb_node->drawData) {
44645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto buffer : drawDataElement.buffers) {
44655cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            auto buffer_state = getBufferState(dev_data, buffer);
44665cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            if (!buffer_state) {
44679a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
44685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                     (uint64_t)(buffer), __LINE__, DRAWSTATE_INVALID_BUFFER, "DS",
4469414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                                     "Cannot submit cmd buffer using deleted buffer 0x%" PRIx64 ".", (uint64_t)(buffer));
44705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else {
44715cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis                buffer_state->in_use.fetch_add(1);
44725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
44735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
44745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
44759a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis    for (auto event : cb_node->writeEventsBeforeWait) {
44764710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        auto event_state = getEventNode(dev_data, event);
4477cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (event_state) event_state->write_in_use++;
4478c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    }
44795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
44805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
44815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4482b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis// Note: This function assumes that the global lock is held by the calling thread.
4483b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis// For the given queue, verify the queue state up to the given seq number.
4484b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis// Currently the only check is to make sure that if there are events to be waited on prior to
4485b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis//  a QueryReset, make sure that all such events have been signalled.
448636c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic bool VerifyQueueStateToSeq(layer_data *dev_data, QUEUE_STATE *queue, uint64_t seq) {
4487b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    bool skip = false;
4488b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    auto queue_seq = queue->seq;
448992b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis    std::unordered_map<VkQueue, uint64_t> other_queue_seqs;
449092b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis    auto sub_it = queue->submissions.begin();
4491b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    while (queue_seq < seq) {
449292b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis        for (auto &wait : sub_it->waitSemaphores) {
449392b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis            auto &last_seq = other_queue_seqs[wait.queue];
449492b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis            last_seq = std::max(last_seq, wait.seq);
449592b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis        }
449692b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis        for (auto cb : sub_it->cbs) {
449792b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis            auto cb_node = getCBNode(dev_data, cb);
4498b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis            if (cb_node) {
4499b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                for (auto queryEventsPair : cb_node->waitedEventsBeforeQueryReset) {
4500b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                    for (auto event : queryEventsPair.second) {
450192b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis                        if (dev_data->eventMap[event].needsSignaled) {
450292b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis                            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
4503b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                                            VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, 0, DRAWSTATE_INVALID_QUERY, "DS",
4504b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                                            "Cannot get query results on queryPool 0x%" PRIx64
4505b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                                            " with index %d which was guarded by unsignaled event 0x%" PRIx64 ".",
4506b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                                            (uint64_t)(queryEventsPair.first.pool), queryEventsPair.first.index, (uint64_t)(event));
4507b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                        }
4508b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                    }
4509b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine                }
4510b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine            }
4511b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine        }
451292b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis        sub_it++;
4513b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis        queue_seq++;
4514b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine    }
451592b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis    for (auto qs : other_queue_seqs) {
451636c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlis        skip |= VerifyQueueStateToSeq(dev_data, getQueueState(dev_data, qs.first), qs.second);
451792b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis    }
4518b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    return skip;
4519b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis}
4520b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis
4521b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis// When the given fence is retired, verify outstanding queue operations through the point of the fence
4522b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlisstatic bool VerifyQueueStateToFence(layer_data *dev_data, VkFence fence) {
4523b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    auto fence_state = getFenceNode(dev_data, fence);
4524b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    if (VK_NULL_HANDLE != fence_state->signaler.first) {
452536c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlis        return VerifyQueueStateToSeq(dev_data, getQueueState(dev_data, fence_state->signaler.first), fence_state->signaler.second);
4526b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    }
4527b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    return false;
4528b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine}
45297d33205c3aa4aba751a2c07f956634aac616f916Chris Forbes
45307d33205c3aa4aba751a2c07f956634aac616f916Chris Forbes// TODO: nuke this completely.
4531b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine// Decrement cmd_buffer in_use and if it goes to 0 remove cmd_buffer from globalInFlightCmdBuffers
4532b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentinestatic inline void removeInFlightCmdBuffer(layer_data *dev_data, VkCommandBuffer cmd_buffer) {
4533b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine    // Pull it off of global list initially, but if we find it in any other queue list, add it back in
4534b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmd_buffer);
4535b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine    pCB->in_use.fetch_sub(1);
4536b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine    if (!pCB->in_use.load()) {
4537b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine        dev_data->globalInFlightCmdBuffers.erase(cmd_buffer);
4538b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine    }
4539b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine}
4540b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine
4541a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis// Decrement in-use count for objects bound to command buffer
45422f8cbf3b166e175174877a59929902e005953d6dTobin Ehlisstatic void DecrementBoundResources(layer_data *dev_data, GLOBAL_CB_NODE const *cb_node) {
454300e8ce2e6c1c191758f7b7c15eeaf350e5b4a3b6Tobin Ehlis    BASE_NODE *base_obj = nullptr;
4544a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    for (auto obj : cb_node->object_bindings) {
45457e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis        base_obj = GetStateStructPtrFromObject(dev_data, obj);
454600e8ce2e6c1c191758f7b7c15eeaf350e5b4a3b6Tobin Ehlis        if (base_obj) {
454700e8ce2e6c1c191758f7b7c15eeaf350e5b4a3b6Tobin Ehlis            base_obj->in_use.fetch_sub(1);
454800e8ce2e6c1c191758f7b7c15eeaf350e5b4a3b6Tobin Ehlis        }
4549a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    }
4550a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis}
4551da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes
455236c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic void RetireWorkOnQueue(layer_data *dev_data, QUEUE_STATE *pQueue, uint64_t seq) {
45539867daedbf52debc77d6568162ee21e071699b80Chris Forbes    std::unordered_map<VkQueue, uint64_t> otherQueueSeqs;
45549867daedbf52debc77d6568162ee21e071699b80Chris Forbes
45559867daedbf52debc77d6568162ee21e071699b80Chris Forbes    // Roll this queue forward, one submission at a time.
45569867daedbf52debc77d6568162ee21e071699b80Chris Forbes    while (pQueue->seq < seq) {
4557bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto &submission = pQueue->submissions.front();
45589867daedbf52debc77d6568162ee21e071699b80Chris Forbes
4559bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        for (auto &wait : submission.waitSemaphores) {
45609867daedbf52debc77d6568162ee21e071699b80Chris Forbes            auto pSemaphore = getSemaphoreNode(dev_data, wait.semaphore);
4561c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            if (pSemaphore) {
4562c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski                pSemaphore->in_use.fetch_sub(1);
4563c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            }
4564bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            auto &lastSeq = otherQueueSeqs[wait.queue];
45659867daedbf52debc77d6568162ee21e071699b80Chris Forbes            lastSeq = std::max(lastSeq, wait.seq);
4566da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes        }
4567cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes
4568bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        for (auto &semaphore : submission.signalSemaphores) {
45699867daedbf52debc77d6568162ee21e071699b80Chris Forbes            auto pSemaphore = getSemaphoreNode(dev_data, semaphore);
4570c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            if (pSemaphore) {
4571c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski                pSemaphore->in_use.fetch_sub(1);
4572c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            }
45739867daedbf52debc77d6568162ee21e071699b80Chris Forbes        }
4574cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes
45759867daedbf52debc77d6568162ee21e071699b80Chris Forbes        for (auto cb : submission.cbs) {
45769a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            auto cb_node = getCBNode(dev_data, cb);
4577c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            if (!cb_node) {
4578c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski                continue;
4579c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            }
4580a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis            // First perform decrement on general case bound objects
45819a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            DecrementBoundResources(dev_data, cb_node);
45829a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            for (auto drawDataElement : cb_node->drawData) {
45839867daedbf52debc77d6568162ee21e071699b80Chris Forbes                for (auto buffer : drawDataElement.buffers) {
45845cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis                    auto buffer_state = getBufferState(dev_data, buffer);
45855cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis                    if (buffer_state) {
45865cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis                        buffer_state->in_use.fetch_sub(1);
45879867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    }
45889867daedbf52debc77d6568162ee21e071699b80Chris Forbes                }
4589da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes            }
45909a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            for (auto event : cb_node->writeEventsBeforeWait) {
45919867daedbf52debc77d6568162ee21e071699b80Chris Forbes                auto eventNode = dev_data->eventMap.find(event);
45929867daedbf52debc77d6568162ee21e071699b80Chris Forbes                if (eventNode != dev_data->eventMap.end()) {
45939867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    eventNode->second.write_in_use--;
45949867daedbf52debc77d6568162ee21e071699b80Chris Forbes                }
45959867daedbf52debc77d6568162ee21e071699b80Chris Forbes            }
45969a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            for (auto queryStatePair : cb_node->queryToStateMap) {
45979867daedbf52debc77d6568162ee21e071699b80Chris Forbes                dev_data->queryToStateMap[queryStatePair.first] = queryStatePair.second;
45989867daedbf52debc77d6568162ee21e071699b80Chris Forbes            }
45999a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            for (auto eventStagePair : cb_node->eventToStageMap) {
46009867daedbf52debc77d6568162ee21e071699b80Chris Forbes                dev_data->eventMap[eventStagePair.first].stageMask = eventStagePair.second;
4601da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes            }
46020a32ed7bdf03e7bda914e03c0bfa6ebf400cdf5bMichael Lentine
46039867daedbf52debc77d6568162ee21e071699b80Chris Forbes            removeInFlightCmdBuffer(dev_data, cb);
46040a32ed7bdf03e7bda914e03c0bfa6ebf400cdf5bMichael Lentine        }
46059867daedbf52debc77d6568162ee21e071699b80Chris Forbes
46069867daedbf52debc77d6568162ee21e071699b80Chris Forbes        auto pFence = getFenceNode(dev_data, submission.fence);
46079867daedbf52debc77d6568162ee21e071699b80Chris Forbes        if (pFence) {
46089867daedbf52debc77d6568162ee21e071699b80Chris Forbes            pFence->state = FENCE_RETIRED;
46090a32ed7bdf03e7bda914e03c0bfa6ebf400cdf5bMichael Lentine        }
46109867daedbf52debc77d6568162ee21e071699b80Chris Forbes
46119867daedbf52debc77d6568162ee21e071699b80Chris Forbes        pQueue->submissions.pop_front();
46129867daedbf52debc77d6568162ee21e071699b80Chris Forbes        pQueue->seq++;
4613b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
46149867daedbf52debc77d6568162ee21e071699b80Chris Forbes
46159867daedbf52debc77d6568162ee21e071699b80Chris Forbes    // Roll other queues forward to the highest seq we saw a wait for
46169867daedbf52debc77d6568162ee21e071699b80Chris Forbes    for (auto qs : otherQueueSeqs) {
461736c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlis        RetireWorkOnQueue(dev_data, getQueueState(dev_data, qs.first), qs.second);
4618d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    }
46199867daedbf52debc77d6568162ee21e071699b80Chris Forbes}
4620651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
4621651d92815dfff917308137bb67aacccc4f60df86Chris Forbes// Submit a fence to a queue, delimiting previous fences and previous untracked
4622651d92815dfff917308137bb67aacccc4f60df86Chris Forbes// work by it.
462336c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic void SubmitFence(QUEUE_STATE *pQueue, FENCE_NODE *pFence, uint64_t submitCount) {
4624cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes    pFence->state = FENCE_INFLIGHT;
46259867daedbf52debc77d6568162ee21e071699b80Chris Forbes    pFence->signaler.first = pQueue->queue;
46269867daedbf52debc77d6568162ee21e071699b80Chris Forbes    pFence->signaler.second = pQueue->seq + pQueue->submissions.size() + submitCount;
4627b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine}
4628b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine
4629e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool validateCommandBufferSimultaneousUse(layer_data *dev_data, GLOBAL_CB_NODE *pCB) {
46305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool skip_call = false;
46315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (dev_data->globalInFlightCmdBuffers.count(pCB->commandBuffer) &&
46325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
4633226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
4634f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                             0, __LINE__, VALIDATION_ERROR_00133, "DS",
4635f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                             "Command Buffer 0x%p is already in use and is not marked for simultaneous use. %s", pCB->commandBuffer,
4636f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                             validation_error_map[VALIDATION_ERROR_00133]);
46375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
46385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
46395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
46405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
464175b0d6603382dcb3e3de24c11ea6e4aa2ef8b4d2Tobin Ehlisstatic bool validateCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB, const char *call_source) {
4642c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis    bool skip = false;
4643cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.command_buffer_state) return skip;
46440a59acde4b40fde3bbfea5811d2abf2c85ca62f4Tobin Ehlis    // Validate ONE_TIME_SUBMIT_BIT CB is not being submitted more than once
46450a59acde4b40fde3bbfea5811d2abf2c85ca62f4Tobin Ehlis    if ((pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) && (pCB->submitCount > 1)) {
4646c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
4647c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis                        __LINE__, DRAWSTATE_COMMAND_BUFFER_SINGLE_SUBMIT_VIOLATION, "DS",
4648226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "Commandbuffer 0x%p was begun w/ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT "
4649c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis                        "set, but has been submitted 0x%" PRIxLEAST64 " times.",
4650226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        pCB->commandBuffer, pCB->submitCount);
46510a59acde4b40fde3bbfea5811d2abf2c85ca62f4Tobin Ehlis    }
46525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Validate that cmd buffers have been updated
46535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (CB_RECORDED != pCB->state) {
46545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (CB_INVALID == pCB->state) {
46555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Inform app of reason CB invalid
4656e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis            for (auto obj : pCB->broken_bindings) {
4657e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis                const char *type_str = object_type_to_string(obj.type);
4658e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis                // Descriptor sets are a special case that can be either destroyed or updated to invalidated a CB
4659e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis                const char *cause_str =
4660e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis                    (obj.type == VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT) ? "destroyed or updated" : "destroyed";
46615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4662c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis                skip |=
46635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
46645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                            reinterpret_cast<uint64_t &>(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
4665226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                            "You are submitting command buffer 0x%p that is invalid because bound %s 0x%" PRIxLEAST64 " was %s.",
4666226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                            pCB->commandBuffer, type_str, obj.handle, cause_str);
46675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
4668cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        } else {  // Flag error for using CB w/o vkEndCommandBuffer() called
4669c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
4670c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis                            (uint64_t)(pCB->commandBuffer), __LINE__, DRAWSTATE_NO_END_COMMAND_BUFFER, "DS",
4671226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                            "You must call vkEndCommandBuffer() on command buffer 0x%p before this call to %s!", pCB->commandBuffer,
4672226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                            call_source);
46735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
46745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
4675c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis    return skip;
46765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
46775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
46787bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski// Validate that queueFamilyIndices of primary command buffers match this queue
46797bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski// Secondary command buffers were previously validated in vkCmdExecuteCommands().
46807bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinskistatic bool validateQueueFamilyIndices(layer_data *dev_data, GLOBAL_CB_NODE *pCB, VkQueue queue) {
46817bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski    bool skip_call = false;
46827bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski    auto pPool = getCommandPoolNode(dev_data, pCB->createInfo.commandPool);
468336c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlis    auto queue_state = getQueueState(dev_data, queue);
46847bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
468536c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlis    if (pPool && queue_state && (pPool->queueFamilyIndex != queue_state->queueFamilyIndex)) {
46867bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
4687f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                             reinterpret_cast<uint64_t>(pCB->commandBuffer), __LINE__, VALIDATION_ERROR_00139, "DS",
4688f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                             "vkQueueSubmit: Primary command buffer 0x%p created in queue family %d is being submitted on queue "
4689f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                             "0x%p from queue family %d. %s",
4690f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                             pCB->commandBuffer, pPool->queueFamilyIndex, queue, queue_state->queueFamilyIndex,
4691f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                             validation_error_map[VALIDATION_ERROR_00139]);
46927bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski    }
46937bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
46947bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski    return skip_call;
46957bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski}
46967bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
4697da8f07baf262972eb3e719fa07b073c180dff157Chris Forbesstatic bool validatePrimaryCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB) {
46985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Track in-use for resources off of primary and any secondary CBs
469983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
4700a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
4701a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes    // If USAGE_SIMULTANEOUS_USE_BIT not set then CB cannot already be executing
4702a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes    // on device
470383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    skip_call |= validateCommandBufferSimultaneousUse(dev_data, pCB);
4704a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
470583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    skip_call |= validateAndIncrementResources(dev_data, pCB);
4706a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
47075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (!pCB->secondaryCommandBuffers.empty()) {
47085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto secondaryCmdBuffer : pCB->secondaryCommandBuffers) {
47095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            GLOBAL_CB_NODE *pSubCB = getCBNode(dev_data, secondaryCmdBuffer);
471083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= validateAndIncrementResources(dev_data, pSubCB);
47114c665b29a9d2906a378417546c7fc6436731d07fTobin Ehlis            if ((pSubCB->primaryCommandBuffer != pCB->commandBuffer) &&
47124c665b29a9d2906a378417546c7fc6436731d07fTobin Ehlis                !(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
4713f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                log_msg(
4714f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
4715f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    __LINE__, VALIDATION_ERROR_00135, "DS",
4716f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    "Commandbuffer 0x%p was submitted with secondary buffer 0x%p but that buffer has subsequently been bound to "
4717f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    "primary cmd buffer 0x%p and it does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set. %s",
4718f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    pCB->commandBuffer, secondaryCmdBuffer, pSubCB->primaryCommandBuffer,
4719f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    validation_error_map[VALIDATION_ERROR_00135]);
47205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
47215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
47225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
4723a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
472475b0d6603382dcb3e3de24c11ea6e4aa2ef8b4d2Tobin Ehlis    skip_call |= validateCommandBufferState(dev_data, pCB, "vkQueueSubmit()");
4725a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
472683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
47275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
47285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4729bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool ValidateFenceForSubmit(layer_data *dev_data, FENCE_NODE *pFence) {
473083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
473181c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes
4732651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    if (pFence) {
4733cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes        if (pFence->state == FENCE_INFLIGHT) {
4734f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen            // TODO: opportunities for VALIDATION_ERROR_00127, VALIDATION_ERROR_01647, VALIDATION_ERROR_01953
473583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
473683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 (uint64_t)(pFence->fence), __LINE__, DRAWSTATE_INVALID_FENCE, "DS",
473783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 "Fence 0x%" PRIx64 " is already in use by another submission.", (uint64_t)(pFence->fence));
4738a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        }
473981c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes
4740cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes        else if (pFence->state == FENCE_RETIRED) {
4741f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen            // TODO: opportunities for VALIDATION_ERROR_00126, VALIDATION_ERROR_01646, VALIDATION_ERROR_01953
474283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |=
474383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
474483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                        reinterpret_cast<uint64_t &>(pFence->fence), __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM",
474583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                        "Fence 0x%" PRIxLEAST64 " submitted in SIGNALED state.  Fences must be reset before being submitted",
474683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                        reinterpret_cast<uint64_t &>(pFence->fence));
4747a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        }
47485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
474981c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes
475083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
475181c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes}
475281c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes
4753bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL QueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence) {
475483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
475581c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map);
475681c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
475781c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
475881c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes
475936c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlis    auto pQueue = getQueueState(dev_data, queue);
4760651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    auto pFence = getFenceNode(dev_data, fence);
476183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    skip_call |= ValidateFenceForSubmit(dev_data, pFence);
476281c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes
476383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (skip_call) {
4764d7d60cccc862fee2d0b3ad410c5fdcc40ddc83aeChris Forbes        return VK_ERROR_VALIDATION_FAILED_EXT;
4765d7d60cccc862fee2d0b3ad410c5fdcc40ddc83aeChris Forbes    }
4766d7d60cccc862fee2d0b3ad410c5fdcc40ddc83aeChris Forbes
4767651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    // Mark the fence in-use.
4768651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    if (pFence) {
47699867daedbf52debc77d6568162ee21e071699b80Chris Forbes        SubmitFence(pQueue, pFence, std::max(1u, submitCount));
4770651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    }
4771651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
47725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Now verify each individual submit
47735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
47745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubmitInfo *submit = &pSubmits[submit_idx];
47759867daedbf52debc77d6568162ee21e071699b80Chris Forbes        vector<SEMAPHORE_WAIT> semaphore_waits;
47769867daedbf52debc77d6568162ee21e071699b80Chris Forbes        vector<VkSemaphore> semaphore_signals;
47775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < submit->waitSemaphoreCount; ++i) {
4778208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis            skip_call |= ValidateStageMaskGsTsEnables(dev_data, submit->pWaitDstStageMask[i], "vkQueueSubmit()",
4779208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                                                      VALIDATION_ERROR_00142, VALIDATION_ERROR_00143);
478001a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            VkSemaphore semaphore = submit->pWaitSemaphores[i];
478101a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            auto pSemaphore = getSemaphoreNode(dev_data, semaphore);
478201a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            if (pSemaphore) {
478301a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes                if (pSemaphore->signaled) {
47849867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    if (pSemaphore->signaler.first != VK_NULL_HANDLE) {
47859867daedbf52debc77d6568162ee21e071699b80Chris Forbes                        semaphore_waits.push_back({semaphore, pSemaphore->signaler.first, pSemaphore->signaler.second});
47869867daedbf52debc77d6568162ee21e071699b80Chris Forbes                        pSemaphore->in_use.fetch_add(1);
47879867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    }
47889867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->signaler.first = VK_NULL_HANDLE;
478901a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes                    pSemaphore->signaled = false;
47901344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                } else {
479183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |=
47921344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
47931344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                                reinterpret_cast<const uint64_t &>(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
4794226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                "Queue 0x%p is waiting on semaphore 0x%" PRIx64 " that has no way to be signaled.", queue,
4795226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                reinterpret_cast<const uint64_t &>(semaphore));
47961344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                }
47975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
47985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
47995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < submit->signalSemaphoreCount; ++i) {
480001a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            VkSemaphore semaphore = submit->pSignalSemaphores[i];
480101a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            auto pSemaphore = getSemaphoreNode(dev_data, semaphore);
480201a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            if (pSemaphore) {
480301a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes                if (pSemaphore->signaled) {
480483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |=
48051344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
48061344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                                reinterpret_cast<const uint64_t &>(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
4807226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                "Queue 0x%p is signaling semaphore 0x%" PRIx64
4808414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                                " that has already been signaled but not waited on by queue 0x%" PRIx64 ".",
4809226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                queue, reinterpret_cast<const uint64_t &>(semaphore),
48109867daedbf52debc77d6568162ee21e071699b80Chris Forbes                                reinterpret_cast<uint64_t &>(pSemaphore->signaler.first));
48111344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                } else {
48129867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->signaler.first = queue;
48139867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->signaler.second = pQueue->seq + pQueue->submissions.size() + 1;
481401a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes                    pSemaphore->signaled = true;
4815da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes                    pSemaphore->in_use.fetch_add(1);
48169867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    semaphore_signals.push_back(semaphore);
48171344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                }
48180a32ed7bdf03e7bda914e03c0bfa6ebf400cdf5bMichael Lentine            }
48195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
4820651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
4821da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes        std::vector<VkCommandBuffer> cbs;
4822da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes
48235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < submit->commandBufferCount; i++) {
4824d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis            auto cb_node = getCBNode(dev_data, submit->pCommandBuffers[i]);
4825d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis            skip_call |= ValidateCmdBufImageLayouts(dev_data, cb_node);
4826d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis            if (cb_node) {
4827da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes                cbs.push_back(submit->pCommandBuffers[i]);
4828d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                for (auto secondaryCmdBuffer : cb_node->secondaryCommandBuffers) {
4829da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes                    cbs.push_back(secondaryCmdBuffer);
4830651d92815dfff917308137bb67aacccc4f60df86Chris Forbes                }
4831651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
4832cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                cb_node->submitCount++;  // increment submit count
4833d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                skip_call |= validatePrimaryCommandBufferState(dev_data, cb_node);
4834d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                skip_call |= validateQueueFamilyIndices(dev_data, cb_node, queue);
4835ea371fa7c8c57edb4d1436e4570cf54f3fc0463fTobin Ehlis                // Potential early exit here as bad object state may crash in delayed function calls
4836cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (skip_call) return result;
48371344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                // Call submit-time functions to validate/update state
4838d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                for (auto &function : cb_node->validate_functions) {
483983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |= function();
48401344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                }
4841d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                for (auto &function : cb_node->eventUpdates) {
484283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |= function(queue);
48431344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                }
4844d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                for (auto &function : cb_node->queryUpdates) {
484583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |= function(queue);
4846d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                }
48471344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis            }
48485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
4849da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes
48509867daedbf52debc77d6568162ee21e071699b80Chris Forbes        pQueue->submissions.emplace_back(cbs, semaphore_waits, semaphore_signals,
48519867daedbf52debc77d6568162ee21e071699b80Chris Forbes                                         submit_idx == submitCount - 1 ? fence : VK_NULL_HANDLE);
48529867daedbf52debc77d6568162ee21e071699b80Chris Forbes    }
48539867daedbf52debc77d6568162ee21e071699b80Chris Forbes
48549867daedbf52debc77d6568162ee21e071699b80Chris Forbes    if (pFence && !submitCount) {
48559867daedbf52debc77d6568162ee21e071699b80Chris Forbes        // If no submissions, but just dropping a fence on the end of the queue,
48569867daedbf52debc77d6568162ee21e071699b80Chris Forbes        // record an empty submission with just the fence, so we can determine
48579867daedbf52debc77d6568162ee21e071699b80Chris Forbes        // its completion.
4858bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pQueue->submissions.emplace_back(std::vector<VkCommandBuffer>(), std::vector<SEMAPHORE_WAIT>(), std::vector<VkSemaphore>(),
48599867daedbf52debc77d6568162ee21e071699b80Chris Forbes                                         fence);
48605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
48619867daedbf52debc77d6568162ee21e071699b80Chris Forbes
4862b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
4863cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) result = dev_data->dispatch_table.QueueSubmit(queue, submitCount, pSubmits, fence);
48645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
48655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
48665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
48675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4868f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultzstatic bool PreCallValidateAllocateMemory(layer_data *dev_data) {
4869f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    bool skip = false;
4870f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    if (dev_data->memObjMap.size() >= dev_data->phys_dev_properties.properties.limits.maxMemoryAllocationCount) {
4871f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
4872f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz                        reinterpret_cast<const uint64_t &>(dev_data->device), __LINE__, VALIDATION_ERROR_00611, "MEM",
4873f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz                        "Number of currently valid memory objects is not less than the maximum allowed (%u). %s",
4874f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz                        dev_data->phys_dev_properties.properties.limits.maxMemoryAllocationCount,
4875f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz                        validation_error_map[VALIDATION_ERROR_00611]);
4876f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    }
4877f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    return skip;
4878f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz}
4879f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz
4880f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultzstatic void PostCallRecordAllocateMemory(layer_data *dev_data, const VkMemoryAllocateInfo *pAllocateInfo, VkDeviceMemory *pMemory) {
4881f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    add_mem_obj_info(dev_data, dev_data->device, *pMemory, pAllocateInfo);
4882f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    return;
4883f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz}
4884f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz
488589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL AllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo,
488689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                              const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory) {
4887f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
4888f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
4889f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    std::unique_lock<std::mutex> lock(global_lock);
4890f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    bool skip = PreCallValidateAllocateMemory(dev_data);
4891f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    if (!skip) {
4892f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        lock.unlock();
4893f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        result = dev_data->dispatch_table.AllocateMemory(device, pAllocateInfo, pAllocator, pMemory);
4894f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        lock.lock();
4895f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        if (VK_SUCCESS == result) {
4896f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz            PostCallRecordAllocateMemory(dev_data, pAllocateInfo, pMemory);
4897f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        }
4898e12739a56d02ca2fb5f0273862668e7475a21a6cMark Lobodzinski    }
48995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
49005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
49015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4902177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis// For given obj node, if it is use, flag a validation error and return callback result, else return false
4903177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlisbool ValidateObjectNotInUse(const layer_data *dev_data, BASE_NODE *obj_node, VK_OBJECT obj_struct,
4904177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis                            UNIQUE_VALIDATION_ERROR_CODE error_code) {
4905cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.object_in_use) return false;
4906177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    bool skip = false;
4907177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    if (obj_node->in_use.load()) {
4908177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, obj_struct.type, obj_struct.handle, __LINE__,
4909177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis                        error_code, "DS", "Cannot delete %s 0x%" PRIx64 " that is currently in use by a command buffer. %s",
4910177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis                        object_type_to_string(obj_struct.type), obj_struct.handle, validation_error_map[error_code]);
4911177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    }
4912177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    return skip;
4913177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis}
49145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4915177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlisstatic bool PreCallValidateFreeMemory(layer_data *dev_data, VkDeviceMemory mem, DEVICE_MEM_INFO **mem_info, VK_OBJECT *obj_struct) {
491694165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *mem_info = getMemObjInfo(dev_data, mem);
491794165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(mem), VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT};
4918cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.free_memory) return false;
4919177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    bool skip = false;
4920177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    if (*mem_info) {
4921177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *mem_info, *obj_struct, VALIDATION_ERROR_00620);
4922177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    }
4923177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    return skip;
4924177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis}
49255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4926177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlisstatic void PostCallRecordFreeMemory(layer_data *dev_data, VkDeviceMemory mem, DEVICE_MEM_INFO *mem_info, VK_OBJECT obj_struct) {
4927177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    // Clear mem binding for any bound objects
492847705d01140c9f1492885e6efc5fa262e7e1c6a0Tobin Ehlis    for (auto obj : mem_info->obj_bindings) {
492947705d01140c9f1492885e6efc5fa262e7e1c6a0Tobin Ehlis        log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, obj.type, obj.handle, __LINE__, MEMTRACK_FREED_MEM_REF,
493047705d01140c9f1492885e6efc5fa262e7e1c6a0Tobin Ehlis                "MEM", "VK Object 0x%" PRIxLEAST64 " still has a reference to mem obj 0x%" PRIxLEAST64, obj.handle,
493147705d01140c9f1492885e6efc5fa262e7e1c6a0Tobin Ehlis                (uint64_t)mem_info->mem);
493247705d01140c9f1492885e6efc5fa262e7e1c6a0Tobin Ehlis        switch (obj.type) {
4933cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT: {
4934cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto image_state = getImageState(dev_data, reinterpret_cast<VkImage &>(obj.handle));
4935cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                assert(image_state);  // Any destroyed images should already be removed from bindings
4936cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                image_state->binding.mem = MEMORY_UNBOUND;
4937cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4938cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4939cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT: {
4940cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto buffer_state = getBufferState(dev_data, reinterpret_cast<VkBuffer &>(obj.handle));
4941cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                assert(buffer_state);  // Any destroyed buffers should already be removed from bindings
4942cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                buffer_state->binding.mem = MEMORY_UNBOUND;
4943cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4944cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4945cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
4946cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // Should only have buffer or image objects bound to memory
4947cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                assert(0);
4948177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        }
4949177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    }
4950177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    // Any bound cmd buffers are now invalid
495139c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, mem_info->cb_bindings, obj_struct);
4952177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    dev_data->memObjMap.erase(mem);
4953177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis}
4954177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis
4955177063aac84fac6f4e650c2629a08b48be643f96Tobin EhlisVKAPI_ATTR void VKAPI_CALL FreeMemory(VkDevice device, VkDeviceMemory mem, const VkAllocationCallbacks *pAllocator) {
4956177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
4957177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    DEVICE_MEM_INFO *mem_info = nullptr;
4958177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    VK_OBJECT obj_struct;
4959b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
4960177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    bool skip = PreCallValidateFreeMemory(dev_data, mem, &mem_info, &obj_struct);
4961177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    if (!skip) {
4962177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        lock.unlock();
4963177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        dev_data->dispatch_table.FreeMemory(device, mem, pAllocator);
4964177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        lock.lock();
4965177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        PostCallRecordFreeMemory(dev_data, mem, mem_info, obj_struct);
496674243a735fe102b370237ddf80d3e6f7ec5246dbMark Mueller    }
49675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
49685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4969f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis// Validate that given Map memory range is valid. This means that the memory should not already be mapped,
4970f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis//  and that the size of the map range should be:
4971f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis//  1. Not zero
4972f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis//  2. Within the size of the memory allocation
4973f57fc64ac43691ad98e1713886b345465573070aTobin Ehlisstatic bool ValidateMapMemRange(layer_data *my_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size) {
497483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
49755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
49765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (size == 0) {
497783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis        skip_call = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
497883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                            (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, "MEM",
497983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                            "VkMapMemory: Attempting to map memory range of size zero");
49805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
49815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
49825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto mem_element = my_data->memObjMap.find(mem);
49835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (mem_element != my_data->memObjMap.end()) {
498457fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        auto mem_info = mem_element->second.get();
49855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // It is an application error to call VkMapMemory on an object that is already mapped
4986de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        if (mem_info->mem_range.size != 0) {
498783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
498883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, "MEM",
498983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                "VkMapMemory: Attempting to map memory on an already-mapped object 0x%" PRIxLEAST64, (uint64_t)mem);
49905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
49915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
49925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Validate that offset + size is within object's allocationSize
49935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (size == VK_WHOLE_SIZE) {
4994de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis            if (offset >= mem_info->alloc_info.allocationSize) {
499583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                skip_call = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
499683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                    VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP,
499783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                    "MEM", "Mapping Memory from 0x%" PRIx64 " to 0x%" PRIx64
499883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                           " with size of VK_WHOLE_SIZE oversteps total array size 0x%" PRIx64,
4999de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis                                    offset, mem_info->alloc_info.allocationSize, mem_info->alloc_info.allocationSize);
50005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
50015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
5002de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis            if ((offset + size) > mem_info->alloc_info.allocationSize) {
5003f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                skip_call = log_msg(
5004f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
5005f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    (uint64_t)mem, __LINE__, VALIDATION_ERROR_00628, "MEM",
5006f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    "Mapping Memory from 0x%" PRIx64 " to 0x%" PRIx64 " oversteps total array size 0x%" PRIx64 ". %s", offset,
5007f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    size + offset, mem_info->alloc_info.allocationSize, validation_error_map[VALIDATION_ERROR_00628]);
50085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
50095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
50105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
501183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
50125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
50135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5014e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic void storeMemRanges(layer_data *my_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size) {
501557fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    auto mem_info = getMemObjInfo(my_data, mem);
501657fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    if (mem_info) {
5017de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        mem_info->mem_range.offset = offset;
5018de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        mem_info->mem_range.size = size;
50195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
50205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
50215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5022e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool deleteMemRanges(layer_data *my_data, VkDeviceMemory mem) {
502383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
502457fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    auto mem_info = getMemObjInfo(my_data, mem);
502557fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    if (mem_info) {
5026de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        if (!mem_info->mem_range.size) {
50275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Valid Usage: memory must currently be mapped
502883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
5029f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                                (uint64_t)mem, __LINE__, VALIDATION_ERROR_00649, "MEM",
5030f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                                "Unmapping Memory without memory being mapped: mem obj 0x%" PRIxLEAST64 ". %s", (uint64_t)mem,
5031f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                                validation_error_map[VALIDATION_ERROR_00649]);
50325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
5033de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        mem_info->mem_range.size = 0;
50345f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski        if (mem_info->shadow_copy) {
50355f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            free(mem_info->shadow_copy_base);
50365f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_copy_base = 0;
50375f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_copy = 0;
50385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
50395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
504083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
50415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
50425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
50435f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski// Guard value for pad data
50445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic char NoncoherentMemoryFillValue = 0xb;
50455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
50465f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinskistatic void initializeAndTrackMemory(layer_data *dev_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size,
50475f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                     void **ppData) {
504857fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    auto mem_info = getMemObjInfo(dev_data, mem);
504957fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    if (mem_info) {
5050de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        mem_info->p_driver_data = *ppData;
5051de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        uint32_t index = mem_info->alloc_info.memoryTypeIndex;
5052b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis        if (dev_data->phys_dev_mem_props.memoryTypes[index].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) {
50535f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_copy = 0;
50545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
50555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (size == VK_WHOLE_SIZE) {
50565f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                size = mem_info->alloc_info.allocationSize - offset;
50575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
50585f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_pad_size = dev_data->phys_dev_properties.properties.limits.minMemoryMapAlignment;
50595f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            assert(vk_safe_modulo(mem_info->shadow_pad_size,
50605f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                  dev_data->phys_dev_properties.properties.limits.minMemoryMapAlignment) == 0);
50615f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            // Ensure start of mapped region reflects hardware alignment constraints
50625f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            uint64_t map_alignment = dev_data->phys_dev_properties.properties.limits.minMemoryMapAlignment;
50635f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski
50645f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            // From spec: (ppData - offset) must be aligned to at least limits::minMemoryMapAlignment.
50655f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            uint64_t start_offset = offset % map_alignment;
50665f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            // Data passed to driver will be wrapped by a guardband of data to detect over- or under-writes.
5067bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            mem_info->shadow_copy_base =
5068bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                malloc(static_cast<size_t>(2 * mem_info->shadow_pad_size + size + map_alignment + start_offset));
50695f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski
50705f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_copy =
50715f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                reinterpret_cast<char *>((reinterpret_cast<uintptr_t>(mem_info->shadow_copy_base) + map_alignment) &
5072bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         ~(map_alignment - 1)) +
5073bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                start_offset;
50745f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            assert(vk_safe_modulo(reinterpret_cast<uintptr_t>(mem_info->shadow_copy) + mem_info->shadow_pad_size - start_offset,
50755f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                  map_alignment) == 0);
50765f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski
50776e17c244b21ce43ac57404a00a0d844039eed363Mark Lobodzinski            memset(mem_info->shadow_copy, NoncoherentMemoryFillValue, static_cast<size_t>(2 * mem_info->shadow_pad_size + size));
50785f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            *ppData = static_cast<char *>(mem_info->shadow_copy) + mem_info->shadow_pad_size;
50795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
50805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
50815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
50825f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski
5083a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis// Verify that state for fence being waited on is appropriate. That is,
50849867daedbf52debc77d6568162ee21e071699b80Chris Forbes//  a fence being waited on should not already be signaled and
5085a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis//  it should have been submitted on a queue or during acquire next image
508649f6132af865afd5b7f413c91125971ac97c135aChris Forbesstatic inline bool verifyWaitFenceState(layer_data *dev_data, VkFence fence, const char *apiCall) {
508783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
50889b48b44dd917f95b5f34dd629ec4076fc87eb3a2Chris Forbes
508949f6132af865afd5b7f413c91125971ac97c135aChris Forbes    auto pFence = getFenceNode(dev_data, fence);
50909b48b44dd917f95b5f34dd629ec4076fc87eb3a2Chris Forbes    if (pFence) {
5091cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes        if (pFence->state == FENCE_UNSIGNALED) {
509283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
509383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 reinterpret_cast<uint64_t &>(fence), __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM",
5094cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "%s called for fence 0x%" PRIxLEAST64
5095cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 " which has not been submitted on a Queue or during "
509683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 "acquire next image.",
509783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 apiCall, reinterpret_cast<uint64_t &>(fence));
50985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
50995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
510083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
51015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
5102a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis
5103b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlisstatic void RetireFence(layer_data *dev_data, VkFence fence) {
5104b3ecd4c1fb44a2e65dfc13256afa9150aabde1d4Chris Forbes    auto pFence = getFenceNode(dev_data, fence);
5105b3ecd4c1fb44a2e65dfc13256afa9150aabde1d4Chris Forbes    if (pFence->signaler.first != VK_NULL_HANDLE) {
510625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Fence signaller is a queue -- use this as proof that prior operations on that queue have completed.
510736c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlis        RetireWorkOnQueue(dev_data, getQueueState(dev_data, pFence->signaler.first), pFence->signaler.second);
5108bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    } else {
510925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Fence signaller is the WSI. We're not tracking what the WSI op actually /was/ in CV yet, but we need to mark
511025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // the fence as retired.
5111d4513979120463171eb479cdded9336eb9944da1Chris Forbes        pFence->state = FENCE_RETIRED;
5112d4513979120463171eb479cdded9336eb9944da1Chris Forbes    }
5113b3ecd4c1fb44a2e65dfc13256afa9150aabde1d4Chris Forbes}
5114b3ecd4c1fb44a2e65dfc13256afa9150aabde1d4Chris Forbes
5115accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlisstatic bool PreCallValidateWaitForFences(layer_data *dev_data, uint32_t fence_count, const VkFence *fences) {
5116cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.wait_for_fences) return false;
5117accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    bool skip = false;
5118accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    for (uint32_t i = 0; i < fence_count; i++) {
5119accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis        skip |= verifyWaitFenceState(dev_data, fences[i], "vkWaitForFences");
5120b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis        skip |= VerifyQueueStateToFence(dev_data, fences[i]);
5121accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    }
5122accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    return skip;
5123accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis}
5124accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis
5125b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlisstatic void PostCallRecordWaitForFences(layer_data *dev_data, uint32_t fence_count, const VkFence *fences, VkBool32 wait_all) {
5126b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    // When we know that all fences are complete we can clean/remove their CBs
5127accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    if ((VK_TRUE == wait_all) || (1 == fence_count)) {
5128accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis        for (uint32_t i = 0; i < fence_count; i++) {
5129b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis            RetireFence(dev_data, fences[i]);
5130accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis        }
5131accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    }
5132accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    // NOTE : Alternate case not handled here is when some fences have completed. In
5133accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    //  this case for app to guarantee which fences completed it will have to call
5134b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    //  vkGetFenceStatus() at which point we'll clean/remove their CBs if complete.
5135accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis}
5136accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis
5137bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL WaitForFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences, VkBool32 waitAll,
5138bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                             uint64_t timeout) {
51395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
51405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Verify fence status of submitted fences
5141b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5142accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    bool skip = PreCallValidateWaitForFences(dev_data, fenceCount, pFences);
5143b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
5144cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
5145a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis
51464a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.WaitForFences(device, fenceCount, pFences, waitAll, timeout);
5147414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller
51485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
5149b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
5150b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis        PostCallRecordWaitForFences(dev_data, fenceCount, pFences, waitAll);
5151b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
51525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
51535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
51545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
51555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5156f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlisstatic bool PreCallValidateGetFenceStatus(layer_data *dev_data, VkFence fence) {
5157cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.get_fence_state) return false;
5158f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis    return verifyWaitFenceState(dev_data, fence, "vkGetFenceStatus");
5159f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis}
5160f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis
5161b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlisstatic void PostCallRecordGetFenceStatus(layer_data *dev_data, VkFence fence) { RetireFence(dev_data, fence); }
5162f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis
516389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL GetFenceStatus(VkDevice device, VkFence fence) {
51645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
5165b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5166f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis    bool skip = PreCallValidateGetFenceStatus(dev_data, fence);
5167b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
5168cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
5169a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis
51704a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.GetFenceStatus(device, fence);
51715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
5172f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis        lock.lock();
5173b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis        PostCallRecordGetFenceStatus(dev_data, fence);
5174f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis        lock.unlock();
51755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
51765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
51775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
51785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
51793b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlisstatic void PostCallRecordGetDeviceQueue(layer_data *dev_data, uint32_t q_family_index, VkQueue queue) {
51803b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    // Add queue to tracking set only if it is new
51813b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    auto result = dev_data->queues.emplace(queue);
51823b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    if (result.second == true) {
518336c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlis        QUEUE_STATE *queue_state = &dev_data->queueMap[queue];
51843b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis        queue_state->queue = queue;
51853b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis        queue_state->queueFamilyIndex = q_family_index;
51863b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis        queue_state->seq = 0;
51873b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    }
51883b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis}
51893b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis
5190bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL GetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue *pQueue) {
51915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
51924a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.GetDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue);
5193b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::lock_guard<std::mutex> lock(global_lock);
5194b376edacad6f7ab3fcc0a914e9b1673a9fcd5143Mark Lobodzinski
51953b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    PostCallRecordGetDeviceQueue(dev_data, queueFamilyIndex, *pQueue);
51965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
51975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
519836c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic bool PreCallValidateQueueWaitIdle(layer_data *dev_data, VkQueue queue, QUEUE_STATE **queue_state) {
519936c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlis    *queue_state = getQueueState(dev_data, queue);
5200cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.queue_wait_idle) return false;
5201e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis    return VerifyQueueStateToSeq(dev_data, *queue_state, (*queue_state)->seq + (*queue_state)->submissions.size());
52024273a1c157585a645dca4c960086032793899d05Tobin Ehlis}
52034273a1c157585a645dca4c960086032793899d05Tobin Ehlis
520436c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic void PostCallRecordQueueWaitIdle(layer_data *dev_data, QUEUE_STATE *queue_state) {
5205e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis    RetireWorkOnQueue(dev_data, queue_state, queue_state->seq + queue_state->submissions.size());
52064273a1c157585a645dca4c960086032793899d05Tobin Ehlis}
52074273a1c157585a645dca4c960086032793899d05Tobin Ehlis
520889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL QueueWaitIdle(VkQueue queue) {
52095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map);
521036c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlis    QUEUE_STATE *queue_state = nullptr;
52119867daedbf52debc77d6568162ee21e071699b80Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
52124273a1c157585a645dca4c960086032793899d05Tobin Ehlis    bool skip = PreCallValidateQueueWaitIdle(dev_data, queue, &queue_state);
52139867daedbf52debc77d6568162ee21e071699b80Chris Forbes    lock.unlock();
5214cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
52154a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.QueueWaitIdle(queue);
52164273a1c157585a645dca4c960086032793899d05Tobin Ehlis    if (VK_SUCCESS == result) {
5217e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis        lock.lock();
5218e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis        PostCallRecordQueueWaitIdle(dev_data, queue_state);
5219e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis        lock.unlock();
52204273a1c157585a645dca4c960086032793899d05Tobin Ehlis    }
52215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
52225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
52235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
52248767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlisstatic bool PreCallValidateDeviceWaitIdle(layer_data *dev_data) {
5225cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.device_wait_idle) return false;
52268767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    bool skip = false;
52278767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    for (auto &queue : dev_data->queueMap) {
52288767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        skip |= VerifyQueueStateToSeq(dev_data, &queue.second, queue.second.seq + queue.second.submissions.size());
52298767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    }
52308767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    return skip;
52318767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis}
52328767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis
52338767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlisstatic void PostCallRecordDeviceWaitIdle(layer_data *dev_data) {
52348767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    for (auto &queue : dev_data->queueMap) {
52358767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        RetireWorkOnQueue(dev_data, &queue.second, queue.second.seq + queue.second.submissions.size());
52368767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    }
52378767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis}
52388767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis
523989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL DeviceWaitIdle(VkDevice device) {
52405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
5241b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
52428767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    bool skip = PreCallValidateDeviceWaitIdle(dev_data);
5243b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
5244cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
52454a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.DeviceWaitIdle(device);
52468767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    if (VK_SUCCESS == result) {
52478767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        lock.lock();
52488767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        PostCallRecordDeviceWaitIdle(dev_data);
52498767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        lock.unlock();
52508767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    }
52515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
52525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
52535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
52541d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlisstatic bool PreCallValidateDestroyFence(layer_data *dev_data, VkFence fence, FENCE_NODE **fence_node, VK_OBJECT *obj_struct) {
52551d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    *fence_node = getFenceNode(dev_data, fence);
52561d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(fence), VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT};
5257cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_fence) return false;
52581d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    bool skip = false;
52591d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    if (*fence_node) {
52601d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        if ((*fence_node)->state == FENCE_INFLIGHT) {
52611d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
5262208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                            (uint64_t)(fence), __LINE__, VALIDATION_ERROR_00173, "DS", "Fence 0x%" PRIx64 " is in use. %s",
5263208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                            (uint64_t)(fence), validation_error_map[VALIDATION_ERROR_00173]);
52641d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        }
52651d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    }
52661d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    return skip;
52671d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis}
52681d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis
52691d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlisstatic void PostCallRecordDestroyFence(layer_data *dev_data, VkFence fence) { dev_data->fenceMap.erase(fence); }
52701d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis
527189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL DestroyFence(VkDevice device, VkFence fence, const VkAllocationCallbacks *pAllocator) {
52725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
52731d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    // Common data objects used pre & post call
52741d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    FENCE_NODE *fence_node = nullptr;
52751d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    VK_OBJECT obj_struct;
5276b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
52771d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    bool skip = PreCallValidateDestroyFence(dev_data, fence, &fence_node, &obj_struct);
52781344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
52791d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    if (!skip) {
52801d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        lock.unlock();
52814a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyFence(device, fence, pAllocator);
52821d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        lock.lock();
52831d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        PostCallRecordDestroyFence(dev_data, fence);
52841d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    }
52855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
52865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5287c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlisstatic bool PreCallValidateDestroySemaphore(layer_data *dev_data, VkSemaphore semaphore, SEMAPHORE_NODE **sema_node,
5288c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis                                            VK_OBJECT *obj_struct) {
5289c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    *sema_node = getSemaphoreNode(dev_data, semaphore);
5290c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(semaphore), VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT};
5291cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_semaphore) return false;
5292c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    bool skip = false;
5293c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    if (*sema_node) {
5294c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *sema_node, *obj_struct, VALIDATION_ERROR_00199);
5295c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    }
5296c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    return skip;
5297c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis}
5298c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis
5299c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlisstatic void PostCallRecordDestroySemaphore(layer_data *dev_data, VkSemaphore sema) { dev_data->semaphoreMap.erase(sema); }
5300c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis
5301bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroySemaphore(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks *pAllocator) {
53025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
5303c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    SEMAPHORE_NODE *sema_node;
5304c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    VK_OBJECT obj_struct;
5305e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
5306c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    bool skip = PreCallValidateDestroySemaphore(dev_data, semaphore, &sema_node, &obj_struct);
5307eafbf0b68ee6ea6e0bf33f07e0058d00a96efd9aTobin Ehlis    if (!skip) {
5308eafbf0b68ee6ea6e0bf33f07e0058d00a96efd9aTobin Ehlis        lock.unlock();
53094a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroySemaphore(device, semaphore, pAllocator);
5310c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis        lock.lock();
5311c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis        PostCallRecordDestroySemaphore(dev_data, semaphore);
531299d938c90c2f000ee73fb13513dacf84ffa5651fMark Mueller    }
53135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
53145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
53154710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlisstatic bool PreCallValidateDestroyEvent(layer_data *dev_data, VkEvent event, EVENT_STATE **event_state, VK_OBJECT *obj_struct) {
531694165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *event_state = getEventNode(dev_data, event);
531794165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(event), VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT};
5318cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_event) return false;
5319d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    bool skip = false;
5320d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    if (*event_state) {
5321d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *event_state, *obj_struct, VALIDATION_ERROR_00213);
5322d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    }
5323d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    return skip;
5324d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis}
5325d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis
53264710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlisstatic void PostCallRecordDestroyEvent(layer_data *dev_data, VkEvent event, EVENT_STATE *event_state, VK_OBJECT obj_struct) {
532739c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, event_state->cb_bindings, obj_struct);
5328d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    dev_data->eventMap.erase(event);
5329d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis}
5330d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis
533189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL DestroyEvent(VkDevice device, VkEvent event, const VkAllocationCallbacks *pAllocator) {
53325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
53334710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis    EVENT_STATE *event_state = nullptr;
5334d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    VK_OBJECT obj_struct;
5335b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5336d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    bool skip = PreCallValidateDestroyEvent(dev_data, event, &event_state, &obj_struct);
5337f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    if (!skip) {
5338f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis        lock.unlock();
53394a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyEvent(device, event, pAllocator);
5340d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis        lock.lock();
5341d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis        PostCallRecordDestroyEvent(dev_data, event, event_state, obj_struct);
5342f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    }
53435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
53445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
534583c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlisstatic bool PreCallValidateDestroyQueryPool(layer_data *dev_data, VkQueryPool query_pool, QUERY_POOL_NODE **qp_state,
534683c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis                                            VK_OBJECT *obj_struct) {
534783c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    *qp_state = getQueryPoolNode(dev_data, query_pool);
534883c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(query_pool), VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT};
5349cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_query_pool) return false;
535083c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    bool skip = false;
535183c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    if (*qp_state) {
535283c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *qp_state, *obj_struct, VALIDATION_ERROR_01012);
535383c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    }
535483c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    return skip;
535583c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis}
535683c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis
5357bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic void PostCallRecordDestroyQueryPool(layer_data *dev_data, VkQueryPool query_pool, QUERY_POOL_NODE *qp_state,
5358bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           VK_OBJECT obj_struct) {
535983c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    invalidateCommandBuffers(dev_data, qp_state->cb_bindings, obj_struct);
536083c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    dev_data->queryPoolMap.erase(query_pool);
536183c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis}
536283c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis
5363bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks *pAllocator) {
5364ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
536583c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    QUERY_POOL_NODE *qp_state = nullptr;
536683c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    VK_OBJECT obj_struct;
5367ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
536883c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    bool skip = PreCallValidateDestroyQueryPool(dev_data, queryPool, &qp_state, &obj_struct);
5369f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    if (!skip) {
5370f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis        lock.unlock();
53714a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyQueryPool(device, queryPool, pAllocator);
537283c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis        lock.lock();
537383c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis        PostCallRecordDestroyQueryPool(dev_data, queryPool, qp_state, obj_struct);
5374f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    }
53755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
53769fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlisstatic bool PreCallValidateGetQueryPoolResults(layer_data *dev_data, VkQueryPool query_pool, uint32_t first_query,
53779fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                               uint32_t query_count, VkQueryResultFlags flags,
53789fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                               unordered_map<QueryObject, vector<VkCommandBuffer>> *queries_in_flight) {
53799fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    for (auto cmd_buffer : dev_data->globalInFlightCmdBuffers) {
53809fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        auto cb = getCBNode(dev_data, cmd_buffer);
53819fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        for (auto query_state_pair : cb->queryToStateMap) {
53829fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            (*queries_in_flight)[query_state_pair.first].push_back(cmd_buffer);
53835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
53845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5385cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.get_query_pool_results) return false;
53869fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    bool skip = false;
53879fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    for (uint32_t i = 0; i < query_count; ++i) {
53889fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        QueryObject query = {query_pool, first_query + i};
53899fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        auto qif_pair = queries_in_flight->find(query);
53909fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        auto query_state_pair = dev_data->queryToStateMap.find(query);
53919fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        if (query_state_pair != dev_data->queryToStateMap.end()) {
5392ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski            // Available and in flight
53939fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            if (qif_pair != queries_in_flight->end() && query_state_pair != dev_data->queryToStateMap.end() &&
53949fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                query_state_pair->second) {
53959fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                for (auto cmd_buffer : qif_pair->second) {
53969fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    auto cb = getCBNode(dev_data, cmd_buffer);
53979fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    auto query_event_pair = cb->waitedEventsBeforeQueryReset.find(query);
53989fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    if (query_event_pair == cb->waitedEventsBeforeQueryReset.end()) {
53999fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
54009fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                        VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
54019fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                        "Cannot get query results on queryPool 0x%" PRIx64 " with index %d which is in flight.",
54029fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                        (uint64_t)(query_pool), first_query + i);
5403ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                    }
5404ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                }
5405ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                // Unavailable and in flight
54069fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            } else if (qif_pair != queries_in_flight->end() && query_state_pair != dev_data->queryToStateMap.end() &&
54079fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                       !query_state_pair->second) {
5408ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                // TODO : Can there be the same query in use by multiple command buffers in flight?
5409ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                bool make_available = false;
54109fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                for (auto cmd_buffer : qif_pair->second) {
54119fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    auto cb = getCBNode(dev_data, cmd_buffer);
54129fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    make_available |= cb->queryToStateMap[query];
5413ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                }
5414ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                if (!(((flags & VK_QUERY_RESULT_PARTIAL_BIT) || (flags & VK_QUERY_RESULT_WAIT_BIT)) && make_available)) {
54159fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
54169fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                    VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
54179fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                    "Cannot get query results on queryPool 0x%" PRIx64 " with index %d which is unavailable.",
54189fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                    (uint64_t)(query_pool), first_query + i);
54195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
5420ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                // Unavailable
54219fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            } else if (query_state_pair != dev_data->queryToStateMap.end() && !query_state_pair->second) {
54229fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0,
54239fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
54249fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                "Cannot get query results on queryPool 0x%" PRIx64 " with index %d which is unavailable.",
54259fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                (uint64_t)(query_pool), first_query + i);
54269fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                // Uninitialized
54279fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            } else if (query_state_pair == dev_data->queryToStateMap.end()) {
54289fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0,
54299fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
54309fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                "Cannot get query results on queryPool 0x%" PRIx64
54319fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                " with index %d as data has not been collected for this index.",
54329fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                (uint64_t)(query_pool), first_query + i);
54335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
54345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
54355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
54369fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    return skip;
54379fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis}
54389fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis
54399fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlisstatic void PostCallRecordGetQueryPoolResults(layer_data *dev_data, VkQueryPool query_pool, uint32_t first_query,
54409fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                              uint32_t query_count,
54419fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                              unordered_map<QueryObject, vector<VkCommandBuffer>> *queries_in_flight) {
54429fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    for (uint32_t i = 0; i < query_count; ++i) {
54439fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        QueryObject query = {query_pool, first_query + i};
54449fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        auto qif_pair = queries_in_flight->find(query);
54459fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        auto query_state_pair = dev_data->queryToStateMap.find(query);
54469fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        if (query_state_pair != dev_data->queryToStateMap.end()) {
54479fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            // Available and in flight
54489fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            if (qif_pair != queries_in_flight->end() && query_state_pair != dev_data->queryToStateMap.end() &&
54499fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                query_state_pair->second) {
54509fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                for (auto cmd_buffer : qif_pair->second) {
54519fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    auto cb = getCBNode(dev_data, cmd_buffer);
54529fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    auto query_event_pair = cb->waitedEventsBeforeQueryReset.find(query);
54539fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    if (query_event_pair != cb->waitedEventsBeforeQueryReset.end()) {
54549fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                        for (auto event : query_event_pair->second) {
54559fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                            dev_data->eventMap[event].needsSignaled = true;
54569fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                        }
54579fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    }
54589fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                }
54599fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            }
54609fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        }
54619fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    }
54629fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis}
54639fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis
54649fdee42cd357379efb9aa27f90beb75d1f824955Tobin EhlisVKAPI_ATTR VkResult VKAPI_CALL GetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount,
54659fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                                   size_t dataSize, void *pData, VkDeviceSize stride, VkQueryResultFlags flags) {
54669fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
54679fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    unordered_map<QueryObject, vector<VkCommandBuffer>> queries_in_flight;
54689fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
54699fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    bool skip = PreCallValidateGetQueryPoolResults(dev_data, queryPool, firstQuery, queryCount, flags, &queries_in_flight);
5470b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
5471cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
54729fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    VkResult result =
54739fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        dev_data->dispatch_table.GetQueryPoolResults(device, queryPool, firstQuery, queryCount, dataSize, pData, stride, flags);
54749fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    lock.lock();
54759fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    PostCallRecordGetQueryPoolResults(dev_data, queryPool, firstQuery, queryCount, &queries_in_flight);
54769fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    lock.unlock();
54779fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    return result;
54785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
54795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5480e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool validateIdleBuffer(const layer_data *my_data, VkBuffer buffer) {
5481e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
54825cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    auto buffer_state = getBufferState(my_data, buffer);
54835cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (!buffer_state) {
54845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
54855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                             (uint64_t)(buffer), __LINE__, DRAWSTATE_DOUBLE_DESTROY, "DS",
5486414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                             "Cannot free buffer 0x%" PRIxLEAST64 " that has not been allocated.", (uint64_t)(buffer));
54875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
54885cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        if (buffer_state->in_use.load()) {
54895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
5490f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                                 (uint64_t)(buffer), __LINE__, VALIDATION_ERROR_00676, "DS",
5491f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                                 "Cannot free buffer 0x%" PRIxLEAST64 " that is in use by a command buffer. %s", (uint64_t)(buffer),
5492f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                                 validation_error_map[VALIDATION_ERROR_00676]);
54935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
54945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
54955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
54965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
54975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5498825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Return true if given ranges intersect, else false
5499825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Prereq : For both ranges, range->end - range->start > 0. This case should have already resulted
5500825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  in an error so not checking that here
5501825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// pad_ranges bool indicates a linear and non-linear comparison which requires padding
5502825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// In the case where padding is required, if an alias is encountered then a validation error is reported and skip_call
5503825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  may be set by the callback function so caller should merge in skip_call value if padding case is possible.
55047dc3fbb89e2dcf3df8fc2e6639a867a959fef3f3Tobin Ehlisstatic bool rangesIntersect(layer_data const *dev_data, MEMORY_RANGE const *range1, MEMORY_RANGE const *range2, bool *skip_call) {
55057dc3fbb89e2dcf3df8fc2e6639a867a959fef3f3Tobin Ehlis    *skip_call = false;
5506825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto r1_start = range1->start;
5507825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto r1_end = range1->end;
5508825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto r2_start = range2->start;
5509825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto r2_end = range2->end;
5510825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    VkDeviceSize pad_align = 1;
5511825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    if (range1->linear != range2->linear) {
5512825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        pad_align = dev_data->phys_dev_properties.properties.limits.bufferImageGranularity;
5513825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    }
5514cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if ((r1_end & ~(pad_align - 1)) < (r2_start & ~(pad_align - 1))) return false;
5515cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if ((r1_start & ~(pad_align - 1)) > (r2_end & ~(pad_align - 1))) return false;
551647aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
5517825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    if (range1->linear != range2->linear) {
551853ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis        // In linear vs. non-linear case, warn of aliasing
5519825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        const char *r1_linear_str = range1->linear ? "Linear" : "Non-linear";
5520825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        const char *r1_type_str = range1->image ? "image" : "buffer";
5521825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        const char *r2_linear_str = range2->linear ? "linear" : "non-linear";
5522825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        const char *r2_type_str = range2->image ? "image" : "buffer";
5523825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        auto obj_type = range1->image ? VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT : VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT;
552453ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis        *skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, obj_type, range1->handle, 0,
552553ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis                              MEMTRACK_INVALID_ALIASING, "MEM", "%s %s 0x%" PRIx64 " is aliased with %s %s 0x%" PRIx64
552653ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis                                                                " which may indicate a bug. For further info refer to the "
552753ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis                                                                "Buffer-Image Granularity section of the Vulkan specification. "
552853ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis                                                                "(https://www.khronos.org/registry/vulkan/specs/1.0-extensions/"
552953ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis                                                                "xhtml/vkspec.html#resources-bufferimagegranularity)",
553053ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis                              r1_linear_str, r1_type_str, range1->handle, r2_linear_str, r2_type_str, range2->handle);
553147aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    }
5532825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    // Ranges intersect
5533825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    return true;
553447aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski}
5535623548a271287ae55415e45e3c654ee66d4e79ffTobin Ehlis// Simplified rangesIntersect that calls above function to check range1 for intersection with offset & end addresses
5536cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlisstatic bool rangesIntersect(layer_data const *dev_data, MEMORY_RANGE const *range1, VkDeviceSize offset, VkDeviceSize end) {
5537825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    // Create a local MEMORY_RANGE struct to wrap offset/size
5538825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    MEMORY_RANGE range_wrap;
5539825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    // Synch linear with range1 to avoid padding and potential validation error case
5540825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range_wrap.linear = range1->linear;
5541825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range_wrap.start = offset;
5542cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    range_wrap.end = end;
5543825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    bool tmp_bool;
55447dc3fbb89e2dcf3df8fc2e6639a867a959fef3f3Tobin Ehlis    return rangesIntersect(dev_data, range1, &range_wrap, &tmp_bool);
5545825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis}
5546cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis// For given mem_info, set all ranges valid that intersect [offset-end] range
5547cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis// TODO : For ranges where there is no alias, we may want to create new buffer ranges that are valid
5548cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlisstatic void SetMemRangesValid(layer_data const *dev_data, DEVICE_MEM_INFO *mem_info, VkDeviceSize offset, VkDeviceSize end) {
5549cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    bool tmp_bool = false;
5550f6e16b28b808a342cb92768001afa2cfeee08a11Tobin Ehlis    MEMORY_RANGE map_range = {};
5551cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    map_range.linear = true;
5552cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    map_range.start = offset;
5553cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    map_range.end = end;
5554cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    for (auto &handle_range_pair : mem_info->bound_ranges) {
55557dc3fbb89e2dcf3df8fc2e6639a867a959fef3f3Tobin Ehlis        if (rangesIntersect(dev_data, &handle_range_pair.second, &map_range, &tmp_bool)) {
5556cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis            // TODO : WARN here if tmp_bool true?
5557cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis            handle_range_pair.second.valid = true;
5558cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis        }
5559cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    }
5560cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis}
5561825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Object with given handle is being bound to memory w/ given mem_info struct.
5562825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  Track the newly bound memory range with given memoryOffset
5563825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  Also scan any previous ranges, track aliased ranges with new range, and flag an error if a linear
5564825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  and non-linear range incorrectly overlap.
5565825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Return true if an error is flagged and the user callback returns "true", otherwise false
5566825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// is_image indicates an image object, otherwise handle is for a buffer
5567825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// is_linear indicates a buffer or linear image
5568825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlisstatic bool InsertMemoryRange(layer_data const *dev_data, uint64_t handle, DEVICE_MEM_INFO *mem_info, VkDeviceSize memoryOffset,
5569825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis                              VkMemoryRequirements memRequirements, bool is_image, bool is_linear) {
5570825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    bool skip_call = false;
55715360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    MEMORY_RANGE range;
5572825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
5573825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range.image = is_image;
557447aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    range.handle = handle;
5575825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range.linear = is_linear;
5576f541bf53dee6daf82a4c8304354eac599a884d29Tobin Ehlis    range.valid = mem_info->global_valid;
5577825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range.memory = mem_info->mem;
557847aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    range.start = memoryOffset;
5579825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range.size = memRequirements.size;
558047aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    range.end = memoryOffset + memRequirements.size - 1;
55815360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    range.aliases.clear();
55825360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    // Update Memory aliasing
558375f4c8cec0996021a4258b9bf920a9e0fea4eac1Tobin Ehlis    // Save aliased ranges so we can copy into final map entry below. Can't do it in loop b/c we don't yet have final ptr. If we
55845360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    // inserted into map before loop to get the final ptr, then we may enter loop when not needed & we check range against itself
55855360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    std::unordered_set<MEMORY_RANGE *> tmp_alias_ranges;
5586825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    for (auto &obj_range_pair : mem_info->bound_ranges) {
5587825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        auto check_range = &obj_range_pair.second;
55885360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis        bool intersection_error = false;
55897dc3fbb89e2dcf3df8fc2e6639a867a959fef3f3Tobin Ehlis        if (rangesIntersect(dev_data, &range, check_range, &intersection_error)) {
5590825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis            skip_call |= intersection_error;
5591825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis            range.aliases.insert(check_range);
55925360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis            tmp_alias_ranges.insert(check_range);
5593825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        }
5594825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    }
55955360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    mem_info->bound_ranges[handle] = std::move(range);
55965360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    for (auto tmp_range : tmp_alias_ranges) {
55975360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis        tmp_range->aliases.insert(&mem_info->bound_ranges[handle]);
55985360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    }
5599825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    if (is_image)
5600825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        mem_info->bound_images.insert(handle);
5601825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    else
5602825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        mem_info->bound_buffers.insert(handle);
5603825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
5604825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    return skip_call;
560547aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski}
560647aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
56079f12a235bb9c014878a98ce385b68587add2538aTobin Ehlisstatic bool InsertImageMemoryRange(layer_data const *dev_data, VkImage image, DEVICE_MEM_INFO *mem_info, VkDeviceSize mem_offset,
5608825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis                                   VkMemoryRequirements mem_reqs, bool is_linear) {
56099f12a235bb9c014878a98ce385b68587add2538aTobin Ehlis    return InsertMemoryRange(dev_data, reinterpret_cast<uint64_t &>(image), mem_info, mem_offset, mem_reqs, true, is_linear);
5610825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis}
5611825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
56129f12a235bb9c014878a98ce385b68587add2538aTobin Ehlisstatic bool InsertBufferMemoryRange(layer_data const *dev_data, VkBuffer buffer, DEVICE_MEM_INFO *mem_info, VkDeviceSize mem_offset,
5613825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis                                    VkMemoryRequirements mem_reqs) {
56149f12a235bb9c014878a98ce385b68587add2538aTobin Ehlis    return InsertMemoryRange(dev_data, reinterpret_cast<uint64_t &>(buffer), mem_info, mem_offset, mem_reqs, false, true);
5615825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis}
5616825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
5617825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Remove MEMORY_RANGE struct for give handle from bound_ranges of mem_info
5618825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  is_image indicates if handle is for image or buffer
5619825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  This function will also remove the handle-to-index mapping from the appropriate
5620825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  map and clean up any aliases for range being removed.
5621825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlisstatic void RemoveMemoryRange(uint64_t handle, DEVICE_MEM_INFO *mem_info, bool is_image) {
5622825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto erase_range = &mem_info->bound_ranges[handle];
5623825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    for (auto alias_range : erase_range->aliases) {
5624825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        alias_range->aliases.erase(erase_range);
562547aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    }
56265360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    erase_range->aliases.clear();
5627825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    mem_info->bound_ranges.erase(handle);
56281cba4e1b5940c6818572e05dcad5a3a47fafbc9eTobin Ehlis    if (is_image) {
5629825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        mem_info->bound_images.erase(handle);
56301cba4e1b5940c6818572e05dcad5a3a47fafbc9eTobin Ehlis    } else {
5631825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        mem_info->bound_buffers.erase(handle);
56321cba4e1b5940c6818572e05dcad5a3a47fafbc9eTobin Ehlis    }
563347aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski}
563447aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
5635825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlisstatic void RemoveBufferMemoryRange(uint64_t handle, DEVICE_MEM_INFO *mem_info) { RemoveMemoryRange(handle, mem_info, false); }
5636825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
5637825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlisstatic void RemoveImageMemoryRange(uint64_t handle, DEVICE_MEM_INFO *mem_info) { RemoveMemoryRange(handle, mem_info, true); }
5638825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
5639e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlisstatic bool PreCallValidateDestroyBuffer(layer_data *dev_data, VkBuffer buffer, BUFFER_STATE **buffer_state,
5640e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis                                         VK_OBJECT *obj_struct) {
5641e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    *buffer_state = getBufferState(dev_data, buffer);
5642e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(buffer), VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT};
5643cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_buffer) return false;
5644e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    bool skip = false;
5645e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    if (*buffer_state) {
5646e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis        skip |= validateIdleBuffer(dev_data, buffer);
5647e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    }
5648e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    return skip;
5649e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis}
5650e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis
5651e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlisstatic void PostCallRecordDestroyBuffer(layer_data *dev_data, VkBuffer buffer, BUFFER_STATE *buffer_state, VK_OBJECT obj_struct) {
5652e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    invalidateCommandBuffers(dev_data, buffer_state->cb_bindings, obj_struct);
5653e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    for (auto mem_binding : buffer_state->GetBoundMemory()) {
5654e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis        auto mem_info = getMemObjInfo(dev_data, mem_binding);
5655e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis        if (mem_info) {
5656e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis            RemoveBufferMemoryRange(reinterpret_cast<uint64_t &>(buffer), mem_info);
5657e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis        }
5658e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    }
5659e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    ClearMemoryObjectBindings(dev_data, reinterpret_cast<uint64_t &>(buffer), VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT);
5660e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    dev_data->bufferMap.erase(buffer_state->buffer);
5661e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis}
5662e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis
5663bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator) {
56645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
5665e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    BUFFER_STATE *buffer_state = nullptr;
5666e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    VK_OBJECT obj_struct;
5667b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5668e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    bool skip = PreCallValidateDestroyBuffer(dev_data, buffer, &buffer_state, &obj_struct);
5669e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    if (!skip) {
5670b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
56714a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyBuffer(device, buffer, pAllocator);
5672e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis        lock.lock();
5673e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis        PostCallRecordDestroyBuffer(dev_data, buffer, buffer_state, obj_struct);
567447aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    }
56755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
56765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
56778e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlisstatic bool PreCallValidateDestroyBufferView(layer_data *dev_data, VkBufferView buffer_view, BUFFER_VIEW_STATE **buffer_view_state,
56788e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis                                             VK_OBJECT *obj_struct) {
567994165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *buffer_view_state = getBufferViewState(dev_data, buffer_view);
568094165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(buffer_view), VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT};
5681cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_buffer_view) return false;
56828e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    bool skip = false;
5683f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    if (*buffer_view_state) {
56841803032f91d772ff3589c9f5a51ade5b299ba538Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *buffer_view_state, *obj_struct, VALIDATION_ERROR_00701);
56858e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    }
56868e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    return skip;
56878e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis}
56888e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis
56898e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlisstatic void PostCallRecordDestroyBufferView(layer_data *dev_data, VkBufferView buffer_view, BUFFER_VIEW_STATE *buffer_view_state,
56908e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis                                            VK_OBJECT obj_struct) {
56918e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    // Any bound cmd buffers are now invalid
569239c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, buffer_view_state->cb_bindings, obj_struct);
5693c6f1a9ab8d9bee0a805a298c9d28f5e81f8877b5Tobin Ehlis    dev_data->bufferViewMap.erase(buffer_view);
56948e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis}
56958e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis
5696bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyBufferView(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks *pAllocator) {
56975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
5698f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    // Common data objects used pre & post call
56998e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    BUFFER_VIEW_STATE *buffer_view_state = nullptr;
57008e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    VK_OBJECT obj_struct;
5701a123662876eebfa844faa65ae3f071d3d77618ebTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
57028e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    // Validate state before calling down chain, update common data if we'll be calling down chain
57038e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    bool skip = PreCallValidateDestroyBufferView(dev_data, bufferView, &buffer_view_state, &obj_struct);
570438e26abbaa884eb48bfec4ddb4e0ae2c90634e06Tobin Ehlis    if (!skip) {
570538e26abbaa884eb48bfec4ddb4e0ae2c90634e06Tobin Ehlis        lock.unlock();
57064a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyBufferView(device, bufferView, pAllocator);
57078e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis        lock.lock();
57088e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis        PostCallRecordDestroyBufferView(dev_data, bufferView, buffer_view_state, obj_struct);
57095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
57105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
57115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
57121facd2c91911508b9fb61f54a56269841299f663Tobin Ehlisstatic bool PreCallValidateDestroyImage(layer_data *dev_data, VkImage image, IMAGE_STATE **image_state, VK_OBJECT *obj_struct) {
571394165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *image_state = getImageState(dev_data, image);
571494165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT};
5715cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_image) return false;
5716f940225c9e5e3e14b3f5a32d3ea360b585614600Tobin Ehlis    bool skip = false;
57172a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    if (*image_state) {
57182a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *image_state, *obj_struct, VALIDATION_ERROR_00743);
5719f940225c9e5e3e14b3f5a32d3ea360b585614600Tobin Ehlis    }
57202a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    return skip;
57212a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis}
5722f940225c9e5e3e14b3f5a32d3ea360b585614600Tobin Ehlis
57231facd2c91911508b9fb61f54a56269841299f663Tobin Ehlisstatic void PostCallRecordDestroyImage(layer_data *dev_data, VkImage image, IMAGE_STATE *image_state, VK_OBJECT obj_struct) {
572439c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, image_state->cb_bindings, obj_struct);
57252a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    // Clean up memory mapping, bindings and range references for image
5726d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis    for (auto mem_binding : image_state->GetBoundMemory()) {
5727d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis        auto mem_info = getMemObjInfo(dev_data, mem_binding);
5728d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis        if (mem_info) {
5729d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            RemoveImageMemoryRange(obj_struct.handle, mem_info);
5730d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis        }
57312a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    }
57324bd8f42e6f6542c0eac2492ce70edc6bebc6a2d8Tobin Ehlis    ClearMemoryObjectBindings(dev_data, obj_struct.handle, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT);
57332a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    // Remove image from imageMap
57342a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    dev_data->imageMap.erase(image);
57352a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis
57362a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    const auto &sub_entry = dev_data->imageSubresourceMap.find(image);
57372a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    if (sub_entry != dev_data->imageSubresourceMap.end()) {
57382a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis        for (const auto &pair : sub_entry->second) {
57392a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis            dev_data->imageLayoutMap.erase(pair);
57405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
57412a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis        dev_data->imageSubresourceMap.erase(sub_entry);
57422a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    }
57432a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis}
57442a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis
57452a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin EhlisVKAPI_ATTR void VKAPI_CALL DestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) {
57462a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
57471facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    IMAGE_STATE *image_state = nullptr;
57482a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    VK_OBJECT obj_struct;
57492a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
57502a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    bool skip = PreCallValidateDestroyImage(dev_data, image, &image_state, &obj_struct);
57512a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    if (!skip) {
5752f940225c9e5e3e14b3f5a32d3ea360b585614600Tobin Ehlis        lock.unlock();
57534a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyImage(device, image, pAllocator);
57542a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis        lock.lock();
57552a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis        PostCallRecordDestroyImage(dev_data, image, image_state, obj_struct);
57565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
57575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
57585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
57594261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinskistatic bool ValidateMemoryTypes(const layer_data *dev_data, const DEVICE_MEM_INFO *mem_info, const uint32_t memory_type_bits,
5760f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                                const char *funcName, UNIQUE_VALIDATION_ERROR_CODE msgCode) {
57614261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinski    bool skip_call = false;
5762de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis    if (((1 << mem_info->alloc_info.memoryTypeIndex) & memory_type_bits) == 0) {
5763f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen        skip_call =
5764f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
5765f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    reinterpret_cast<const uint64_t &>(mem_info->mem), __LINE__, msgCode, "MT",
5766f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    "%s(): MemoryRequirements->memoryTypeBits (0x%X) for this object type are not compatible with the memory "
5767f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    "type (0x%X) of this memory object 0x%" PRIx64 ". %s",
5768f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    funcName, memory_type_bits, mem_info->alloc_info.memoryTypeIndex,
5769f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    reinterpret_cast<const uint64_t &>(mem_info->mem), validation_error_map[msgCode]);
57704261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinski    }
57714261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinski    return skip_call;
57724261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinski}
57734261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinski
5774bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL BindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
577558070a671b39e2058a799c7b9c932f3f03f2e66dTobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
57765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
5777b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
57785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Track objects tied to memory
57799f12a235bb9c014878a98ce385b68587add2538aTobin Ehlis    uint64_t buffer_handle = reinterpret_cast<uint64_t &>(buffer);
5780888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    bool skip_call = SetMemBinding(dev_data, mem, buffer_handle, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, "vkBindBufferMemory");
57815cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    auto buffer_state = getBufferState(dev_data, buffer);
57825cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (buffer_state) {
57832eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        if (!buffer_state->memory_requirements_checked) {
57842eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            // There's not an explicit requirement in the spec to call vkGetBufferMemoryRequirements() prior to calling
57852eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            //  BindBufferMemory but it's implied in that memory being bound must conform with VkMemoryRequirements from
57862eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            //  vkGetBufferMemoryRequirements()
57872eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
57882eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis                                 buffer_handle, __LINE__, DRAWSTATE_INVALID_BUFFER, "DS",
57892eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis                                 "vkBindBufferMemory(): Binding memory to buffer 0x%" PRIxLEAST64
57902eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis                                 " but vkGetBufferMemoryRequirements() has not been called on that buffer.",
57912eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis                                 buffer_handle);
57922eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            // Make the call for them so we can verify the state
57932eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            lock.unlock();
57942eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            dev_data->dispatch_table.GetBufferMemoryRequirements(device, buffer, &buffer_state->requirements);
57952eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            lock.lock();
57962eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        }
57975cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        buffer_state->binding.mem = mem;
57985cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        buffer_state->binding.offset = memoryOffset;
57992eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        buffer_state->binding.size = buffer_state->requirements.size;
580047aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
580147aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski        // Track and validate bound memory range information
580257fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        auto mem_info = getMemObjInfo(dev_data, mem);
580357fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        if (mem_info) {
58042eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            skip_call |= InsertBufferMemoryRange(dev_data, buffer, mem_info, memoryOffset, buffer_state->requirements);
5805f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen            skip_call |= ValidateMemoryTypes(dev_data, mem_info, buffer_state->requirements.memoryTypeBits, "vkBindBufferMemory()",
5806f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                                             VALIDATION_ERROR_00797);
580747aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski        }
580847aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
58092c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves        // Validate memory requirements alignment
58102eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        if (vk_safe_modulo(memoryOffset, buffer_state->requirements.alignment) != 0) {
5811f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
5812f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                                 VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, VALIDATION_ERROR_02174, "DS",
5813cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "vkBindBufferMemory(): memoryOffset is 0x%" PRIxLEAST64
5814cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 " but must be an integer multiple of the "
5815f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                                 "VkMemoryRequirements::alignment value 0x%" PRIxLEAST64
5816f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                                 ", returned from a call to vkGetBufferMemoryRequirements with buffer. %s",
5817f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                                 memoryOffset, buffer_state->requirements.alignment, validation_error_map[VALIDATION_ERROR_02174]);
58182c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves        }
5819ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller
58202c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves        // Validate device limits alignments
5821ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller        static const VkBufferUsageFlagBits usage_list[3] = {
5822ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller            static_cast<VkBufferUsageFlagBits>(VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT),
5823bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT};
5824bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        static const char *memory_type[3] = {"texel", "uniform", "storage"};
5825bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        static const char *offset_name[3] = {"minTexelBufferOffsetAlignment", "minUniformBufferOffsetAlignment",
5826bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                             "minStorageBufferOffsetAlignment"};
5827cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski
5828cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        // TODO:  vk_validation_stats.py cannot abide braces immediately preceeding or following a validation error enum
5829cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        // clang-format off
5830cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        static const UNIQUE_VALIDATION_ERROR_CODE msgCode[3] = { VALIDATION_ERROR_00794, VALIDATION_ERROR_00795,
5831cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                                 VALIDATION_ERROR_00796 };
5832cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        // clang-format on
5833ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller
5834ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller        // Keep this one fresh!
5835ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller        const VkDeviceSize offset_requirement[3] = {
5836ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller            dev_data->phys_dev_properties.properties.limits.minTexelBufferOffsetAlignment,
5837ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller            dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment,
5838bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            dev_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment};
58398718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis        VkBufferUsageFlags usage = dev_data->bufferMap[buffer].get()->createInfo.usage;
5840ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller
5841ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller        for (int i = 0; i < 3; i++) {
5842ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller            if (usage & usage_list[i]) {
5843ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller                if (vk_safe_modulo(memoryOffset, offset_requirement[i]) != 0) {
5844cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip_call |= log_msg(
5845cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0,
5846cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        __LINE__, msgCode[i], "DS", "vkBindBufferMemory(): %s memoryOffset is 0x%" PRIxLEAST64
5847cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                    " but must be a multiple of "
5848cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                    "device limit %s 0x%" PRIxLEAST64 ". %s",
5849cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        memory_type[i], memoryOffset, offset_name[i], offset_requirement[i], validation_error_map[msgCode[i]]);
5850ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller                }
58512c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves            }
58522c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves        }
58535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5854b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
585583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (!skip_call) {
58564a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.BindBufferMemory(device, buffer, mem, memoryOffset);
58575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
58585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
58595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
58605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5861bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL GetBufferMemoryRequirements(VkDevice device, VkBuffer buffer,
5862bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                       VkMemoryRequirements *pMemoryRequirements) {
586315caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
586415caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    dev_data->dispatch_table.GetBufferMemoryRequirements(device, buffer, pMemoryRequirements);
58655cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    auto buffer_state = getBufferState(dev_data, buffer);
586615caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    if (buffer_state) {
586715caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis        buffer_state->requirements = *pMemoryRequirements;
58682eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        buffer_state->memory_requirements_checked = true;
586915caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    }
58705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
58715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5872bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL GetImageMemoryRequirements(VkDevice device, VkImage image, VkMemoryRequirements *pMemoryRequirements) {
587315caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
587415caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    dev_data->dispatch_table.GetImageMemoryRequirements(device, image, pMemoryRequirements);
587515caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    auto image_state = getImageState(dev_data, image);
587615caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    if (image_state) {
587715caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis        image_state->requirements = *pMemoryRequirements;
58782eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        image_state->memory_requirements_checked = true;
587915caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    }
58805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
5881593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
5882f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlisstatic bool PreCallValidateDestroyImageView(layer_data *dev_data, VkImageView image_view, IMAGE_VIEW_STATE **image_view_state,
5883f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis                                            VK_OBJECT *obj_struct) {
588494165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *image_view_state = getImageViewState(dev_data, image_view);
588594165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(image_view), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT};
5886cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_image_view) return false;
5887f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    bool skip = false;
5888f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    if (*image_view_state) {
58891803032f91d772ff3589c9f5a51ade5b299ba538Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *image_view_state, *obj_struct, VALIDATION_ERROR_00776);
5890f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    }
5891f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    return skip;
5892f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis}
5893f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis
5894f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlisstatic void PostCallRecordDestroyImageView(layer_data *dev_data, VkImageView image_view, IMAGE_VIEW_STATE *image_view_state,
5895f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis                                           VK_OBJECT obj_struct) {
5896f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    // Any bound cmd buffers are now invalid
589739c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, image_view_state->cb_bindings, obj_struct);
5898f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    dev_data->imageViewMap.erase(image_view);
5899f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis}
5900f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis
5901bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyImageView(VkDevice device, VkImageView imageView, const VkAllocationCallbacks *pAllocator) {
5902d85c42a6c1d6ad7a6f684c5bd793aab482b7705cTobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
5903f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    // Common data objects used pre & post call
5904f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    IMAGE_VIEW_STATE *image_view_state = nullptr;
5905f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    VK_OBJECT obj_struct;
5906a123662876eebfa844faa65ae3f071d3d77618ebTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
5907f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    bool skip = PreCallValidateDestroyImageView(dev_data, imageView, &image_view_state, &obj_struct);
5908d85c42a6c1d6ad7a6f684c5bd793aab482b7705cTobin Ehlis    if (!skip) {
5909d85c42a6c1d6ad7a6f684c5bd793aab482b7705cTobin Ehlis        lock.unlock();
59104a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyImageView(device, imageView, pAllocator);
5911f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis        lock.lock();
5912f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis        PostCallRecordDestroyImageView(dev_data, imageView, image_view_state, obj_struct);
5913d85c42a6c1d6ad7a6f684c5bd793aab482b7705cTobin Ehlis    }
59145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
59155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5916bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyShaderModule(VkDevice device, VkShaderModule shaderModule,
5917bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                               const VkAllocationCallbacks *pAllocator) {
5918918c283ac4f8c604b79abd0c8b5706d2a7352a34Chris Forbes    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
5919918c283ac4f8c604b79abd0c8b5706d2a7352a34Chris Forbes
5920b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5921918c283ac4f8c604b79abd0c8b5706d2a7352a34Chris Forbes    my_data->shaderModuleMap.erase(shaderModule);
5922b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
5923918c283ac4f8c604b79abd0c8b5706d2a7352a34Chris Forbes
59244a0754042cf090e131e9e769d8a3633c228625beChris Forbes    my_data->dispatch_table.DestroyShaderModule(device, shaderModule, pAllocator);
59255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
59265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
59274c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic bool PreCallValidateDestroyPipeline(layer_data *dev_data, VkPipeline pipeline, PIPELINE_STATE **pipeline_state,
59288bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis                                           VK_OBJECT *obj_struct) {
592994165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *pipeline_state = getPipelineState(dev_data, pipeline);
593094165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(pipeline), VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT};
5931cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_pipeline) return false;
59328bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    bool skip = false;
59338bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    if (*pipeline_state) {
59341803032f91d772ff3589c9f5a51ade5b299ba538Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *pipeline_state, *obj_struct, VALIDATION_ERROR_00555);
59358bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    }
59368bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    return skip;
59378bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis}
59388bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis
59394c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic void PostCallRecordDestroyPipeline(layer_data *dev_data, VkPipeline pipeline, PIPELINE_STATE *pipeline_state,
59408bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis                                          VK_OBJECT obj_struct) {
59418bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    // Any bound cmd buffers are now invalid
594239c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, pipeline_state->cb_bindings, obj_struct);
59438bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    dev_data->pipelineMap.erase(pipeline);
59448bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis}
59458bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis
5946bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyPipeline(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks *pAllocator) {
5947a86b57cf1145ee63d5997547ac0f9847933fc3b6Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
59484c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    PIPELINE_STATE *pipeline_state = nullptr;
59498bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    VK_OBJECT obj_struct;
5950e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
59518bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    bool skip = PreCallValidateDestroyPipeline(dev_data, pipeline, &pipeline_state, &obj_struct);
5952f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    if (!skip) {
5953f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis        lock.unlock();
59544a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyPipeline(device, pipeline, pAllocator);
59558bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis        lock.lock();
59568bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis        PostCallRecordDestroyPipeline(dev_data, pipeline, pipeline_state, obj_struct);
5957f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    }
59585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
59595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5960bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyPipelineLayout(VkDevice device, VkPipelineLayout pipelineLayout,
5961bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkAllocationCallbacks *pAllocator) {
59626792ea7cc0ce5fa64b7bd6c946460608cbda91c7Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
5963e28cddb35c63274c13873b9a7060ad43b255c6f1Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
59646792ea7cc0ce5fa64b7bd6c946460608cbda91c7Tobin Ehlis    dev_data->pipelineLayoutMap.erase(pipelineLayout);
5965e28cddb35c63274c13873b9a7060ad43b255c6f1Tobin Ehlis    lock.unlock();
5966e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis
59674a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.DestroyPipelineLayout(device, pipelineLayout, pAllocator);
59685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
59695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5970d31a44af6da568692a73201825459689c9431867Tobin Ehlisstatic bool PreCallValidateDestroySampler(layer_data *dev_data, VkSampler sampler, SAMPLER_STATE **sampler_state,
5971806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis                                          VK_OBJECT *obj_struct) {
597294165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *sampler_state = getSamplerState(dev_data, sampler);
597394165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(sampler), VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT};
5974cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_sampler) return false;
5975806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    bool skip = false;
5976806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    if (*sampler_state) {
5977806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *sampler_state, *obj_struct, VALIDATION_ERROR_00837);
5978806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    }
5979806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    return skip;
5980806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis}
5981806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis
5982d31a44af6da568692a73201825459689c9431867Tobin Ehlisstatic void PostCallRecordDestroySampler(layer_data *dev_data, VkSampler sampler, SAMPLER_STATE *sampler_state,
5983806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis                                         VK_OBJECT obj_struct) {
5984806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    // Any bound cmd buffers are now invalid
5985cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (sampler_state) invalidateCommandBuffers(dev_data, sampler_state->cb_bindings, obj_struct);
5986806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    dev_data->samplerMap.erase(sampler);
5987806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis}
5988806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis
5989bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroySampler(VkDevice device, VkSampler sampler, const VkAllocationCallbacks *pAllocator) {
599056f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
5991d31a44af6da568692a73201825459689c9431867Tobin Ehlis    SAMPLER_STATE *sampler_state = nullptr;
5992806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    VK_OBJECT obj_struct;
599356f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
5994806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    bool skip = PreCallValidateDestroySampler(dev_data, sampler, &sampler_state, &obj_struct);
5995f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    if (!skip) {
5996f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis        lock.unlock();
59974a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroySampler(device, sampler, pAllocator);
5998806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis        lock.lock();
5999806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis        PostCallRecordDestroySampler(dev_data, sampler, sampler_state, obj_struct);
6000f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    }
60015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
60025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
600379c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlisstatic void PostCallRecordDestroyDescriptorSetLayout(layer_data *dev_data, VkDescriptorSetLayout ds_layout) {
600479c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis    dev_data->descriptorSetLayoutMap.erase(ds_layout);
600579c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis}
600679c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis
6007bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyDescriptorSetLayout(VkDevice device, VkDescriptorSetLayout descriptorSetLayout,
6008bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      const VkAllocationCallbacks *pAllocator) {
600979c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
601079c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis    dev_data->dispatch_table.DestroyDescriptorSetLayout(device, descriptorSetLayout, pAllocator);
601179c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
601279c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis    PostCallRecordDestroyDescriptorSetLayout(dev_data, descriptorSetLayout);
60135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
60145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6015c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlisstatic bool PreCallValidateDestroyDescriptorPool(layer_data *dev_data, VkDescriptorPool pool,
6016a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis                                                 DESCRIPTOR_POOL_STATE **desc_pool_state, VK_OBJECT *obj_struct) {
601794165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *desc_pool_state = getDescriptorPoolState(dev_data, pool);
601894165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(pool), VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT};
6019cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_descriptor_pool) return false;
6020c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    bool skip = false;
6021c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    if (*desc_pool_state) {
60221803032f91d772ff3589c9f5a51ade5b299ba538Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *desc_pool_state, *obj_struct, VALIDATION_ERROR_00901);
6023c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    }
6024c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    return skip;
6025c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis}
6026c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis
6027c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlisstatic void PostCallRecordDestroyDescriptorPool(layer_data *dev_data, VkDescriptorPool descriptorPool,
6028a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis                                                DESCRIPTOR_POOL_STATE *desc_pool_state, VK_OBJECT obj_struct) {
6029c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    // Any bound cmd buffers are now invalid
603039c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, desc_pool_state->cb_bindings, obj_struct);
6031c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    // Free sets that were in this pool
6032c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    for (auto ds : desc_pool_state->sets) {
6033c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis        freeDescriptorSet(dev_data, ds);
6034c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    }
6035c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    dev_data->descriptorPoolMap.erase(descriptorPool);
6036c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis}
6037c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis
6038bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool,
6039bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkAllocationCallbacks *pAllocator) {
6040c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
6041a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis    DESCRIPTOR_POOL_STATE *desc_pool_state = nullptr;
6042c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    VK_OBJECT obj_struct;
6043c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
6044c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    bool skip = PreCallValidateDestroyDescriptorPool(dev_data, descriptorPool, &desc_pool_state, &obj_struct);
6045c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    if (!skip) {
6046c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis        lock.unlock();
6047c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis        dev_data->dispatch_table.DestroyDescriptorPool(device, descriptorPool, pAllocator);
6048c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis        lock.lock();
6049c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis        PostCallRecordDestroyDescriptorPool(dev_data, descriptorPool, desc_pool_state, obj_struct);
6050c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    }
60515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
6052bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis// Verify cmdBuffer in given cb_node is not in global in-flight set, and return skip_call result
6053bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis//  If this is a secondary command buffer, then make sure its primary is also in-flight
6054bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis//  If primary is not in-flight, then remove secondary from global in-flight set
6055bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis// This function is only valid at a point when cmdBuffer is being reset or freed
6056cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlisstatic bool checkCommandBufferInFlight(layer_data *dev_data, const GLOBAL_CB_NODE *cb_node, const char *action,
6057cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis                                       UNIQUE_VALIDATION_ERROR_CODE error_code) {
6058bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    bool skip_call = false;
6059bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    if (dev_data->globalInFlightCmdBuffers.count(cb_node->commandBuffer)) {
6060bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        // Primary CB or secondary where primary is also in-flight is an error
6061bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        if ((cb_node->createInfo.level != VK_COMMAND_BUFFER_LEVEL_SECONDARY) ||
6062bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis            (dev_data->globalInFlightCmdBuffers.count(cb_node->primaryCommandBuffer))) {
6063cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis            skip_call |=
6064cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6065cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis                        reinterpret_cast<const uint64_t &>(cb_node->commandBuffer), __LINE__, error_code, "DS",
6066226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "Attempt to %s command buffer (0x%p) which is in use. %s", action, cb_node->commandBuffer,
6067226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        validation_error_map[error_code]);
6068bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        }
6069bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    }
6070bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    return skip_call;
6071bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis}
6072a964cad279f9749cd9ebfc7555247ff3bff26d53Chris Forbes
6073bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis// Iterate over all cmdBuffers in given commandPool and verify that each is not in use
6074cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlisstatic bool checkCommandBuffersInFlight(layer_data *dev_data, COMMAND_POOL_NODE *pPool, const char *action,
6075cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis                                        UNIQUE_VALIDATION_ERROR_CODE error_code) {
6076bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    bool skip_call = false;
6077a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes    for (auto cmd_buffer : pPool->commandBuffers) {
6078a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes        if (dev_data->globalInFlightCmdBuffers.count(cmd_buffer)) {
6079cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis            skip_call |= checkCommandBufferInFlight(dev_data, getCBNode(dev_data, cmd_buffer), action, error_code);
6080bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        }
6081bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    }
6082bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    return skip_call;
6083bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis}
60845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6085a01b5eb150981aad061238e64b173d0da8c11140Chris Forbesstatic void clearCommandBuffersInFlight(layer_data *dev_data, COMMAND_POOL_NODE *pPool) {
6086a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes    for (auto cmd_buffer : pPool->commandBuffers) {
6087a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes        dev_data->globalInFlightCmdBuffers.erase(cmd_buffer);
6088a964cad279f9749cd9ebfc7555247ff3bff26d53Chris Forbes    }
6089a964cad279f9749cd9ebfc7555247ff3bff26d53Chris Forbes}
6090a964cad279f9749cd9ebfc7555247ff3bff26d53Chris Forbes
6091bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL FreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount,
6092bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              const VkCommandBuffer *pCommandBuffers) {
60935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
60945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool skip_call = false;
6095b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
6096c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes
60975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < commandBufferCount; i++) {
60989f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        auto cb_node = getCBNode(dev_data, pCommandBuffers[i]);
60995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Delete CB information structure, and remove from commandBufferMap
61009f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        if (cb_node) {
6101cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis            skip_call |= checkCommandBufferInFlight(dev_data, cb_node, "free", VALIDATION_ERROR_00096);
6102c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes        }
6103c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes    }
6104c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes
6105cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return;
6106c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes
6107c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes    auto pPool = getCommandPoolNode(dev_data, commandPool);
6108c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes    for (uint32_t i = 0; i < commandBufferCount; i++) {
61099f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        auto cb_node = getCBNode(dev_data, pCommandBuffers[i]);
6110c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes        // Delete CB information structure, and remove from commandBufferMap
61119f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        if (cb_node) {
61129f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis            dev_data->globalInFlightCmdBuffers.erase(cb_node->commandBuffer);
61135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // reset prior to delete for data clean-up
61149f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis            resetCB(dev_data, cb_node->commandBuffer);
61159f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis            dev_data->commandBufferMap.erase(cb_node->commandBuffer);
61169f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis            delete cb_node;
61175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
61185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
61195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Remove commandBuffer reference from commandPoolMap
6120c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes        pPool->commandBuffers.remove(pCommandBuffers[i]);
61215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6122b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
6123e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis
61244a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.FreeCommandBuffers(device, commandPool, commandBufferCount, pCommandBuffers);
61255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
61265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
612789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo *pCreateInfo,
6128bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkAllocationCallbacks *pAllocator, VkCommandPool *pCommandPool) {
61295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
61305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
61314a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateCommandPool(device, pCreateInfo, pAllocator, pCommandPool);
61325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
61335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6134b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
61355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->commandPoolMap[*pCommandPool].createFlags = pCreateInfo->flags;
61365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->commandPoolMap[*pCommandPool].queueFamilyIndex = pCreateInfo->queueFamilyIndex;
61375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
61385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
61395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
61405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
614189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo *pCreateInfo,
614289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                               const VkAllocationCallbacks *pAllocator, VkQueryPool *pQueryPool) {
61435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
61440c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    bool skip = false;
61450c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    if (pCreateInfo && pCreateInfo->queryType == VK_QUERY_TYPE_PIPELINE_STATISTICS) {
61460c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis        if (!dev_data->enabled_features.pipelineStatisticsQuery) {
61470c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0,
61480c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis                            __LINE__, VALIDATION_ERROR_01006, "DS",
61490c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis                            "Query pool with type VK_QUERY_TYPE_PIPELINE_STATISTICS created on a device "
61500c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis                            "with VkDeviceCreateInfo.pEnabledFeatures.pipelineStatisticsQuery == VK_FALSE. %s",
61510c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis                            validation_error_map[VALIDATION_ERROR_01006]);
61520c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis        }
61530c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    }
61540c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis
61550c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
61560c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    if (!skip) {
61570c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis        result = dev_data->dispatch_table.CreateQueryPool(device, pCreateInfo, pAllocator, pQueryPool);
61580c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    }
61595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
6160b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
6161eafbf0b68ee6ea6e0bf33f07e0058d00a96efd9aTobin Ehlis        QUERY_POOL_NODE *qp_node = &dev_data->queryPoolMap[*pQueryPool];
6162eafbf0b68ee6ea6e0bf33f07e0058d00a96efd9aTobin Ehlis        qp_node->createInfo = *pCreateInfo;
61635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
61645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
61655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
61665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
61675f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlisstatic bool PreCallValidateDestroyCommandPool(layer_data *dev_data, VkCommandPool pool, COMMAND_POOL_NODE **cp_state) {
616894165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *cp_state = getCommandPoolNode(dev_data, pool);
6169cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_command_pool) return false;
61705f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    bool skip = false;
61715f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    if (*cp_state) {
61725f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        // Verify that command buffers in pool are complete (not in-flight)
61735f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        skip |= checkCommandBuffersInFlight(dev_data, *cp_state, "destroy command pool with", VALIDATION_ERROR_00077);
61745f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    }
61755f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    return skip;
61765f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis}
61775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
61785f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlisstatic void PostCallRecordDestroyCommandPool(layer_data *dev_data, VkCommandPool pool, COMMAND_POOL_NODE *cp_state) {
61799f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis    // Must remove cmdpool from cmdpoolmap, after removing all cmdbuffers in its list from the commandBufferMap
61805f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    clearCommandBuffersInFlight(dev_data, cp_state);
61815f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    for (auto cb : cp_state->commandBuffers) {
6182a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes        clear_cmd_buf_and_mem_references(dev_data, cb);
61839f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        auto cb_node = getCBNode(dev_data, cb);
6184d61de0e68063faa169a9a632f811c9c9adec9897Tobin Ehlis        // Remove references to this cb_node prior to delete
6185d61de0e68063faa169a9a632f811c9c9adec9897Tobin Ehlis        // TODO : Need better solution here, resetCB?
61867165385f3a39f1f951f3a6a9a06ed2cce4642b6dMark Lobodzinski        for (auto obj : cb_node->object_bindings) {
61877165385f3a39f1f951f3a6a9a06ed2cce4642b6dMark Lobodzinski            removeCommandBufferBinding(dev_data, &obj, cb_node);
61887165385f3a39f1f951f3a6a9a06ed2cce4642b6dMark Lobodzinski        }
6189d61de0e68063faa169a9a632f811c9c9adec9897Tobin Ehlis        for (auto framebuffer : cb_node->framebuffers) {
6190c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis            auto fb_state = getFramebufferState(dev_data, framebuffer);
6191cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (fb_state) fb_state->cb_bindings.erase(cb_node);
6192d61de0e68063faa169a9a632f811c9c9adec9897Tobin Ehlis        }
6193cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        dev_data->commandBufferMap.erase(cb);  // Remove this command buffer
6194cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        delete cb_node;                        // delete CB info structure
6195a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes    }
61965f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    dev_data->commandPoolMap.erase(pool);
61975f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis}
6198e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis
61995f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis// Destroy commandPool along with all of the commandBuffers allocated from that pool
62005f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin EhlisVKAPI_ATTR void VKAPI_CALL DestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks *pAllocator) {
62015f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
62025f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    COMMAND_POOL_NODE *cp_state = nullptr;
62035f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
62045f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    bool skip = PreCallValidateDestroyCommandPool(dev_data, commandPool, &cp_state);
62055f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    if (!skip) {
62065f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        lock.unlock();
62075f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        dev_data->dispatch_table.DestroyCommandPool(device, commandPool, pAllocator);
62085f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        lock.lock();
62095f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        PostCallRecordDestroyCommandPool(dev_data, commandPool, cp_state);
62105f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    }
62115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
62125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6213bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL ResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags) {
62145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
621583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
6216400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis
62171ec6311a8537f4467db08eacbd762ebaa87e70b0Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
6218a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes    auto pPool = getCommandPoolNode(dev_data, commandPool);
6219cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis    skip_call |= checkCommandBuffersInFlight(dev_data, pPool, "reset command pool with", VALIDATION_ERROR_00072);
62201ec6311a8537f4467db08eacbd762ebaa87e70b0Chris Forbes    lock.unlock();
6221a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes
6222cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
62235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
62244a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.ResetCommandPool(device, commandPool, flags);
62255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
62265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Reset all of the CBs allocated from this pool
62275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
62281ec6311a8537f4467db08eacbd762ebaa87e70b0Chris Forbes        lock.lock();
6229a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes        clearCommandBuffersInFlight(dev_data, pPool);
6230a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes        for (auto cmdBuffer : pPool->commandBuffers) {
6231a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes            resetCB(dev_data, cmdBuffer);
62325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
62331ec6311a8537f4467db08eacbd762ebaa87e70b0Chris Forbes        lock.unlock();
62345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
62355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
62365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
62375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
623889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL ResetFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences) {
62395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
624083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
6241b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
62425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < fenceCount; ++i) {
6243df1846b33487b02061c0ff42d768588a9abeb6c7Chris Forbes        auto pFence = getFenceNode(dev_data, pFences[i]);
6244090da73358f71ba026e2474a822fecf55267d166Chris Forbes        if (pFence && pFence->state == FENCE_INFLIGHT) {
624583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
62464527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 reinterpret_cast<const uint64_t &>(pFences[i]), __LINE__, VALIDATION_ERROR_00183, "DS",
62474527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 "Fence 0x%" PRIx64 " is in use. %s", reinterpret_cast<const uint64_t &>(pFences[i]),
62484527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 validation_error_map[VALIDATION_ERROR_00183]);
62495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
62505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6251b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
6252090da73358f71ba026e2474a822fecf55267d166Chris Forbes
6253cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
6254090da73358f71ba026e2474a822fecf55267d166Chris Forbes
62554a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.ResetFences(device, fenceCount, pFences);
6256090da73358f71ba026e2474a822fecf55267d166Chris Forbes
6257090da73358f71ba026e2474a822fecf55267d166Chris Forbes    if (result == VK_SUCCESS) {
6258090da73358f71ba026e2474a822fecf55267d166Chris Forbes        lock.lock();
6259090da73358f71ba026e2474a822fecf55267d166Chris Forbes        for (uint32_t i = 0; i < fenceCount; ++i) {
6260090da73358f71ba026e2474a822fecf55267d166Chris Forbes            auto pFence = getFenceNode(dev_data, pFences[i]);
6261090da73358f71ba026e2474a822fecf55267d166Chris Forbes            if (pFence) {
6262090da73358f71ba026e2474a822fecf55267d166Chris Forbes                pFence->state = FENCE_UNSIGNALED;
6263090da73358f71ba026e2474a822fecf55267d166Chris Forbes            }
6264090da73358f71ba026e2474a822fecf55267d166Chris Forbes        }
6265090da73358f71ba026e2474a822fecf55267d166Chris Forbes        lock.unlock();
6266090da73358f71ba026e2474a822fecf55267d166Chris Forbes    }
6267090da73358f71ba026e2474a822fecf55267d166Chris Forbes
62685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
62695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
62705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6271e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis// For given cb_nodes, invalidate them and track object causing invalidation
62720a4087f99558069e9f6a437ff2dbb5a9c1c22ccaTobin Ehlisvoid invalidateCommandBuffers(const layer_data *dev_data, std::unordered_set<GLOBAL_CB_NODE *> const &cb_nodes, VK_OBJECT obj) {
6273e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis    for (auto cb_node : cb_nodes) {
627439c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis        if (cb_node->state == CB_RECORDING) {
627539c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis            log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6276fefa20333f94ea75877cca53d0631542cd9d0432Tobin Ehlis                    (uint64_t)(cb_node->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
6277226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    "Invalidating a command buffer that's currently being recorded: 0x%p.", cb_node->commandBuffer);
627839c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis        }
6279e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis        cb_node->state = CB_INVALID;
6280e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis        cb_node->broken_bindings.push_back(obj);
6281e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis    }
6282e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis}
6283e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis
6284c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlisstatic bool PreCallValidateDestroyFramebuffer(layer_data *dev_data, VkFramebuffer framebuffer,
6285c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis                                              FRAMEBUFFER_STATE **framebuffer_state, VK_OBJECT *obj_struct) {
628694165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *framebuffer_state = getFramebufferState(dev_data, framebuffer);
628794165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(framebuffer), VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT};
6288cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_framebuffer) return false;
6289728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    bool skip = false;
6290728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    if (*framebuffer_state) {
6291728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *framebuffer_state, *obj_struct, VALIDATION_ERROR_00422);
6292728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    }
6293728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    return skip;
6294728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis}
6295728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis
6296c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlisstatic void PostCallRecordDestroyFramebuffer(layer_data *dev_data, VkFramebuffer framebuffer, FRAMEBUFFER_STATE *framebuffer_state,
6297728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis                                             VK_OBJECT obj_struct) {
629839c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, framebuffer_state->cb_bindings, obj_struct);
6299728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    dev_data->frameBufferMap.erase(framebuffer);
6300728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis}
6301728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis
6302bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyFramebuffer(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks *pAllocator) {
63035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
6304c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    FRAMEBUFFER_STATE *framebuffer_state = nullptr;
6305728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    VK_OBJECT obj_struct;
6306b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
6307728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    bool skip = PreCallValidateDestroyFramebuffer(dev_data, framebuffer, &framebuffer_state, &obj_struct);
6308728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    if (!skip) {
6309728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis        lock.unlock();
6310728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis        dev_data->dispatch_table.DestroyFramebuffer(device, framebuffer, pAllocator);
6311728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis        lock.lock();
6312728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis        PostCallRecordDestroyFramebuffer(dev_data, framebuffer, framebuffer_state, obj_struct);
63135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
63145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
63155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
63160ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlisstatic bool PreCallValidateDestroyRenderPass(layer_data *dev_data, VkRenderPass render_pass, RENDER_PASS_STATE **rp_state,
63170ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis                                             VK_OBJECT *obj_struct) {
631894165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *rp_state = getRenderPassState(dev_data, render_pass);
631994165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(render_pass), VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT};
6320cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_renderpass) return false;
63210ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    bool skip = false;
63220ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    if (*rp_state) {
63230ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *rp_state, *obj_struct, VALIDATION_ERROR_00393);
63240ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    }
63250ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    return skip;
63260ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis}
63270ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis
63280ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlisstatic void PostCallRecordDestroyRenderPass(layer_data *dev_data, VkRenderPass render_pass, RENDER_PASS_STATE *rp_state,
63290ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis                                            VK_OBJECT obj_struct) {
633039c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, rp_state->cb_bindings, obj_struct);
63310ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    dev_data->renderPassMap.erase(render_pass);
63320ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis}
63330ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis
6334bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks *pAllocator) {
63355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
63360ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    RENDER_PASS_STATE *rp_state = nullptr;
63370ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    VK_OBJECT obj_struct;
6338e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
63390ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    bool skip = PreCallValidateDestroyRenderPass(dev_data, renderPass, &rp_state, &obj_struct);
6340a9fbfe0c622e9fa4b56ddd015ed4c3c409020c2eTobin Ehlis    if (!skip) {
6341a9fbfe0c622e9fa4b56ddd015ed4c3c409020c2eTobin Ehlis        lock.unlock();
63424a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyRenderPass(device, renderPass, pAllocator);
63430ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis        lock.lock();
63440ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis        PostCallRecordDestroyRenderPass(dev_data, renderPass, rp_state, obj_struct);
6345a9fbfe0c622e9fa4b56ddd015ed4c3c409020c2eTobin Ehlis    }
63465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
63475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
634889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo,
634989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                            const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer) {
63505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
63514f38db6ace251a2f5302c9de6c5d7c791a610505Karl Schultz    // TODO: Add check for VALIDATION_ERROR_00658
63524f38db6ace251a2f5302c9de6c5d7c791a610505Karl Schultz    // TODO: Add check for VALIDATION_ERROR_00666
63534f38db6ace251a2f5302c9de6c5d7c791a610505Karl Schultz    // TODO: Add check for VALIDATION_ERROR_00667
63544f38db6ace251a2f5302c9de6c5d7c791a610505Karl Schultz    // TODO: Add check for VALIDATION_ERROR_00668
63554f38db6ace251a2f5302c9de6c5d7c791a610505Karl Schultz    // TODO: Add check for VALIDATION_ERROR_00669
63564a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateBuffer(device, pCreateInfo, pAllocator, pBuffer);
63575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
63585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6359b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
63605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // TODO : This doesn't create deep copy of pQueueFamilyIndices so need to fix that if/when we want that data to be valid
63615cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        dev_data->bufferMap.insert(std::make_pair(*pBuffer, unique_ptr<BUFFER_STATE>(new BUFFER_STATE(*pBuffer, pCreateInfo))));
63625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
63635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
63645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
63655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
63668c07a094dc9cc4afb6b62181f341c12b9e969041Mark Youngstatic bool PreCallValidateCreateBufferView(layer_data *dev_data, const VkBufferViewCreateInfo *pCreateInfo) {
63678c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    bool skip_call = false;
63685cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    BUFFER_STATE *buffer_state = getBufferState(dev_data, pCreateInfo->buffer);
63698c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    // If this isn't a sparse buffer, it needs to have memory backing it at CreateBufferView time
63705cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (buffer_state) {
637135ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis        skip_call |= ValidateMemoryIsBoundToBuffer(dev_data, buffer_state, "vkCreateBufferView()", VALIDATION_ERROR_02522);
6372cf64d39a58d4903515232a17eea47ff3ed82faadTobin Ehlis        // In order to create a valid buffer view, the buffer must have been created with at least one of the
6373cf64d39a58d4903515232a17eea47ff3ed82faadTobin Ehlis        // following flags:  UNIFORM_TEXEL_BUFFER_BIT or STORAGE_TEXEL_BUFFER_BIT
63741b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes        skip_call |= ValidateBufferUsageFlags(
63755cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            dev_data, buffer_state, VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT, false,
63761b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes            VALIDATION_ERROR_00694, "vkCreateBufferView()", "VK_BUFFER_USAGE_[STORAGE|UNIFORM]_TEXEL_BUFFER_BIT");
6377b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    }
63788c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    return skip_call;
63798c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young}
63808c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young
638189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateBufferView(VkDevice device, const VkBufferViewCreateInfo *pCreateInfo,
638289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                const VkAllocationCallbacks *pAllocator, VkBufferView *pView) {
63835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
63848c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    std::unique_lock<std::mutex> lock(global_lock);
63858c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    bool skip_call = PreCallValidateCreateBufferView(dev_data, pCreateInfo);
63868c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    lock.unlock();
6387cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
63884a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateBufferView(device, pCreateInfo, pAllocator, pView);
63895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
63908c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young        lock.lock();
639139267c0c27b8f032f05a6747eb02d4508247fdc1Tobin Ehlis        dev_data->bufferViewMap[*pView] = unique_ptr<BUFFER_VIEW_STATE>(new BUFFER_VIEW_STATE(*pView, pCreateInfo));
63928c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young        lock.unlock();
63935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
63945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
63955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
63965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
639789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo,
639889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                           const VkAllocationCallbacks *pAllocator, VkImage *pImage) {
63995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
640047892024546c67e8db98b51b2ddb962c21088894Mark Lobodzinski
64014a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateImage(device, pCreateInfo, pAllocator, pImage);
64025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
64035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6404b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
6405071ef2b0d7ff4089667300bfd4a8d9e495010ccdMark Lobodzinski        PostCallRecordCreateImage(&dev_data->imageMap, &dev_data->imageSubresourceMap, &dev_data->imageLayoutMap, pCreateInfo,
6406071ef2b0d7ff4089667300bfd4a8d9e495010ccdMark Lobodzinski                                  pImage);
64075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
64085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
64095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
64105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
64115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic void ResolveRemainingLevelsLayers(layer_data *dev_data, VkImageSubresourceRange *range, VkImage image) {
641225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Expects global_lock to be held by caller
64135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
64141facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    auto image_state = getImageState(dev_data, image);
64151facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (image_state) {
641625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // If the caller used the special values VK_REMAINING_MIP_LEVELS and VK_REMAINING_ARRAY_LAYERS, resolve them now in our
641725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // internal state to the actual values.
64185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (range->levelCount == VK_REMAINING_MIP_LEVELS) {
64191facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            range->levelCount = image_state->createInfo.mipLevels - range->baseMipLevel;
64205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
64215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
64225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (range->layerCount == VK_REMAINING_ARRAY_LAYERS) {
64231facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            range->layerCount = image_state->createInfo.arrayLayers - range->baseArrayLayer;
64245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
64255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
64265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
64275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
64285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Return the correct layer/level counts if the caller used the special
64295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// values VK_REMAINING_MIP_LEVELS or VK_REMAINING_ARRAY_LAYERS.
64305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic void ResolveRemainingLevelsLayers(layer_data *dev_data, uint32_t *levels, uint32_t *layers, VkImageSubresourceRange range,
64315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                         VkImage image) {
643225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Expects global_lock to be held by caller
64335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
64345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    *levels = range.levelCount;
64355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    *layers = range.layerCount;
64361facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    auto image_state = getImageState(dev_data, image);
64371facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (image_state) {
64385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (range.levelCount == VK_REMAINING_MIP_LEVELS) {
64391facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            *levels = image_state->createInfo.mipLevels - range.baseMipLevel;
64405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
64415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (range.layerCount == VK_REMAINING_ARRAY_LAYERS) {
64421facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            *layers = image_state->createInfo.arrayLayers - range.baseArrayLayer;
64435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
64445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
64455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
64465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6447a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis// For the given format verify that the aspect masks make sense
6448a4a1923d21087ded8e990190acd6752264712319Tobin Ehlisstatic bool ValidateImageAspectMask(layer_data *dev_data, VkImage image, VkFormat format, VkImageAspectFlags aspect_mask,
6449a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                    const char *func_name) {
6450a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis    bool skip = false;
6451a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis    if (vk_format_is_color(format)) {
6452a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis        if ((aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) != VK_IMAGE_ASPECT_COLOR_BIT) {
6453a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
6454a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            (uint64_t)image, __LINE__, VALIDATION_ERROR_00741, "IMAGE",
6455a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            "%s: Color image formats must have the VK_IMAGE_ASPECT_COLOR_BIT set. %s", func_name,
6456a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_00741]);
6457767f34f4f3da5d183123359c4f612149fbe595dfTobin Ehlis        } else if ((aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) != aspect_mask) {
6458a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
6459a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            (uint64_t)image, __LINE__, VALIDATION_ERROR_00741, "IMAGE",
6460a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            "%s: Color image formats must have ONLY the VK_IMAGE_ASPECT_COLOR_BIT set. %s", func_name,
6461a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_00741]);
6462a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis        }
6463a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis    } else if (vk_format_is_depth_and_stencil(format)) {
6464a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis        if ((aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) == 0) {
6465a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
6466cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            (uint64_t)image, __LINE__, VALIDATION_ERROR_00741, "IMAGE",
6467cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s: Depth/stencil image formats must have "
6468cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "at least one of VK_IMAGE_ASPECT_DEPTH_BIT "
6469cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "and VK_IMAGE_ASPECT_STENCIL_BIT set. %s",
6470a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            func_name, validation_error_map[VALIDATION_ERROR_00741]);
6471767f34f4f3da5d183123359c4f612149fbe595dfTobin Ehlis        } else if ((aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != aspect_mask) {
6472a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
6473a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            (uint64_t)image, __LINE__, VALIDATION_ERROR_00741, "IMAGE",
6474a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            "%s: Combination depth/stencil image formats can have only the VK_IMAGE_ASPECT_DEPTH_BIT and "
6475a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            "VK_IMAGE_ASPECT_STENCIL_BIT set. %s",
6476a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            func_name, validation_error_map[VALIDATION_ERROR_00741]);
6477a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis        }
6478a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis    } else if (vk_format_is_depth_only(format)) {
6479a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis        if ((aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) != VK_IMAGE_ASPECT_DEPTH_BIT) {
6480a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
6481a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            (uint64_t)image, __LINE__, VALIDATION_ERROR_00741, "IMAGE",
6482a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            "%s: Depth-only image formats must have the VK_IMAGE_ASPECT_DEPTH_BIT set. %s", func_name,
6483a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_00741]);
6484767f34f4f3da5d183123359c4f612149fbe595dfTobin Ehlis        } else if ((aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) != aspect_mask) {
6485a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
6486a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            (uint64_t)image, __LINE__, VALIDATION_ERROR_00741, "IMAGE",
6487a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            "%s: Depth-only image formats can have only the VK_IMAGE_ASPECT_DEPTH_BIT set. %s", func_name,
6488a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_00741]);
6489a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis        }
6490a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis    } else if (vk_format_is_stencil_only(format)) {
6491a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis        if ((aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) != VK_IMAGE_ASPECT_STENCIL_BIT) {
6492a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
6493a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            (uint64_t)image, __LINE__, VALIDATION_ERROR_00741, "IMAGE",
6494a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            "%s: Stencil-only image formats must have the VK_IMAGE_ASPECT_STENCIL_BIT set. %s", func_name,
6495a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_00741]);
6496767f34f4f3da5d183123359c4f612149fbe595dfTobin Ehlis        } else if ((aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) != aspect_mask) {
6497a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
6498a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            (uint64_t)image, __LINE__, VALIDATION_ERROR_00741, "IMAGE",
6499a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            "%s: Stencil-only image formats can have only the VK_IMAGE_ASPECT_STENCIL_BIT set. %s", func_name,
6500a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_00741]);
6501a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis        }
6502a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis    }
6503a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis    return skip;
6504a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis}
6505a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis
6506364a03b109f0b2b37be2e13d293fa93b8af5203aMike Weiblenstatic bool ValidateImageSubrangeLevelLayerCounts(layer_data *dev_data, const VkImageSubresourceRange &subresourceRange,
6507364a03b109f0b2b37be2e13d293fa93b8af5203aMike Weiblen                                                  const char *func_name, UNIQUE_VALIDATION_ERROR_CODE layer_msg_code,
6508364a03b109f0b2b37be2e13d293fa93b8af5203aMike Weiblen                                                  UNIQUE_VALIDATION_ERROR_CODE level_msg_code) {
6509364a03b109f0b2b37be2e13d293fa93b8af5203aMike Weiblen    bool skip = false;
6510364a03b109f0b2b37be2e13d293fa93b8af5203aMike Weiblen    if (subresourceRange.levelCount == 0) {
6511364a03b109f0b2b37be2e13d293fa93b8af5203aMike Weiblen        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
6512364a03b109f0b2b37be2e13d293fa93b8af5203aMike Weiblen                        VALIDATION_ERROR_00768, "IMAGE", "%s called with 0 in subresourceRange.levelCount. %s", func_name,
6513364a03b109f0b2b37be2e13d293fa93b8af5203aMike Weiblen                        validation_error_map[VALIDATION_ERROR_00768]);
6514364a03b109f0b2b37be2e13d293fa93b8af5203aMike Weiblen    }
6515364a03b109f0b2b37be2e13d293fa93b8af5203aMike Weiblen    if (subresourceRange.layerCount == 0) {
6516364a03b109f0b2b37be2e13d293fa93b8af5203aMike Weiblen        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
6517364a03b109f0b2b37be2e13d293fa93b8af5203aMike Weiblen                        VALIDATION_ERROR_00769, "IMAGE", "%s called with 0 in subresourceRange.layerCount. %s", func_name,
6518364a03b109f0b2b37be2e13d293fa93b8af5203aMike Weiblen                        validation_error_map[VALIDATION_ERROR_00769]);
6519364a03b109f0b2b37be2e13d293fa93b8af5203aMike Weiblen    }
6520364a03b109f0b2b37be2e13d293fa93b8af5203aMike Weiblen    return skip;
6521364a03b109f0b2b37be2e13d293fa93b8af5203aMike Weiblen}
6522364a03b109f0b2b37be2e13d293fa93b8af5203aMike Weiblen
6523a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlisstatic bool PreCallValidateCreateImageView(layer_data *dev_data, const VkImageViewCreateInfo *create_info) {
6524e3effabf8e97cae8e006477806ceaca62e4f2ce7Tobin Ehlis    bool skip = false;
6525a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis    IMAGE_STATE *image_state = getImageState(dev_data, create_info->image);
65261facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (image_state) {
6527e3effabf8e97cae8e006477806ceaca62e4f2ce7Tobin Ehlis        skip |= ValidateImageUsageFlags(
65281facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            dev_data, image_state, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT |
65291facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis                                       VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
65301b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes            false, -1, "vkCreateImageView()",
65315a8cba534d14ce341ba7a2100a542e93f0e3033cTony Barbour            "VK_IMAGE_USAGE_[SAMPLED|STORAGE|COLOR_ATTACHMENT|DEPTH_STENCIL_ATTACHMENT|INPUT_ATTACHMENT]_BIT");
6532b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski        // If this isn't a sparse image, it needs to have memory backing it at CreateImageView time
653335ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis        skip |= ValidateMemoryIsBoundToImage(dev_data, image_state, "vkCreateImageView()", VALIDATION_ERROR_02524);
6534a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis        // Checks imported from image layer
6535a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis        if (create_info->subresourceRange.baseMipLevel >= image_state->createInfo.mipLevels) {
6536a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis            std::stringstream ss;
6537a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis            ss << "vkCreateImageView called with baseMipLevel " << create_info->subresourceRange.baseMipLevel << " for image "
6538a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis               << create_info->image << " that only has " << image_state->createInfo.mipLevels << " mip levels.";
6539a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis            skip |=
6540a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
6541a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis                        VALIDATION_ERROR_00768, "IMAGE", "%s %s", ss.str().c_str(), validation_error_map[VALIDATION_ERROR_00768]);
6542a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis        }
6543a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis        if (create_info->subresourceRange.baseArrayLayer >= image_state->createInfo.arrayLayers) {
6544a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis            std::stringstream ss;
6545a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis            ss << "vkCreateImageView called with baseArrayLayer " << create_info->subresourceRange.baseArrayLayer << " for image "
6546a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis               << create_info->image << " that only has " << image_state->createInfo.arrayLayers << " array layers.";
6547a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis            skip |=
6548a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
6549a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis                        VALIDATION_ERROR_00769, "IMAGE", "%s %s", ss.str().c_str(), validation_error_map[VALIDATION_ERROR_00769]);
6550a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis        }
6551a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis        // TODO: Need new valid usage language for levelCount == 0 & layerCount == 0
6552364a03b109f0b2b37be2e13d293fa93b8af5203aMike Weiblen        skip |= ValidateImageSubrangeLevelLayerCounts(dev_data, create_info->subresourceRange, "vkCreateImageView()",
6553364a03b109f0b2b37be2e13d293fa93b8af5203aMike Weiblen                                                      VALIDATION_ERROR_00768, VALIDATION_ERROR_00769);
6554a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis
6555a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis        VkImageCreateFlags image_flags = image_state->createInfo.flags;
6556a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis        VkFormat image_format = image_state->createInfo.format;
6557a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis        VkFormat view_format = create_info->format;
6558a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis        VkImageAspectFlags aspect_mask = create_info->subresourceRange.aspectMask;
6559a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis
6560a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis        // Validate VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT state
6561a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis        if (image_flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) {
6562a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis            // Format MUST be compatible (in the same format compatibility class) as the format the image was created with
6563a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis            if (vk_format_get_compatibility_class(image_format) != vk_format_get_compatibility_class(view_format)) {
6564a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis                std::stringstream ss;
6565a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis                ss << "vkCreateImageView(): ImageView format " << string_VkFormat(view_format)
6566a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis                   << " is not in the same format compatibility class as image (" << (uint64_t)create_info->image << ")  format "
6567a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis                   << string_VkFormat(image_format) << ".  Images created with the VK_IMAGE_CREATE_MUTABLE_FORMAT BIT "
6568a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis                   << "can support ImageViews with differing formats but they must be in the same compatibility class.";
6569a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
6570a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis                                VALIDATION_ERROR_02171, "IMAGE", "%s %s", ss.str().c_str(),
6571a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis                                validation_error_map[VALIDATION_ERROR_02171]);
6572a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis            }
6573a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis        } else {
6574a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis            // Format MUST be IDENTICAL to the format the image was created with
6575a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis            if (image_format != view_format) {
6576a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis                std::stringstream ss;
6577a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis                ss << "vkCreateImageView() format " << string_VkFormat(view_format) << " differs from image "
6578a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis                   << (uint64_t)create_info->image << " format " << string_VkFormat(image_format)
6579a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis                   << ".  Formats MUST be IDENTICAL unless VK_IMAGE_CREATE_MUTABLE_FORMAT BIT was set on image creation.";
6580a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
6581a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis                                VALIDATION_ERROR_02172, "IMAGE", "%s %s", ss.str().c_str(),
6582a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis                                validation_error_map[VALIDATION_ERROR_02172]);
6583a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis            }
6584a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis        }
6585a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis
6586a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis        // Validate correct image aspect bits for desired formats and format consistency
6587a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis        skip |= ValidateImageAspectMask(dev_data, image_state->image, image_format, aspect_mask, "vkCreateImageView()");
6588bb6624cb996175d8945190886a200e720b3871efChris Forbes    }
6589e3effabf8e97cae8e006477806ceaca62e4f2ce7Tobin Ehlis    return skip;
65908c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young}
6591bb6624cb996175d8945190886a200e720b3871efChris Forbes
6592a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlisstatic inline void PostCallRecordCreateImageView(layer_data *dev_data, const VkImageViewCreateInfo *create_info, VkImageView view) {
6593a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis    dev_data->imageViewMap[view] = unique_ptr<IMAGE_VIEW_STATE>(new IMAGE_VIEW_STATE(view, create_info));
6594a7660be5cf06febf98b35674796b8d2e53c77155Tobin Ehlis    ResolveRemainingLevelsLayers(dev_data, &dev_data->imageViewMap[view].get()->create_info.subresourceRange, create_info->image);
65958c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young}
6596bb6624cb996175d8945190886a200e720b3871efChris Forbes
65978c07a094dc9cc4afb6b62181f341c12b9e969041Mark YoungVKAPI_ATTR VkResult VKAPI_CALL CreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo,
65988c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young                                               const VkAllocationCallbacks *pAllocator, VkImageView *pView) {
65998c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
66008c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    std::unique_lock<std::mutex> lock(global_lock);
6601e3effabf8e97cae8e006477806ceaca62e4f2ce7Tobin Ehlis    bool skip = PreCallValidateCreateImageView(dev_data, pCreateInfo);
66028c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    lock.unlock();
6603cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
66044a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateImageView(device, pCreateInfo, pAllocator, pView);
66055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
66068c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young        lock.lock();
660779fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis        PostCallRecordCreateImageView(dev_data, pCreateInfo, *pView);
66088c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young        lock.unlock();
66095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6610bb6624cb996175d8945190886a200e720b3871efChris Forbes
66115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
66125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
66135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6614bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateFence(VkDevice device, const VkFenceCreateInfo *pCreateInfo,
6615bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           const VkAllocationCallbacks *pAllocator, VkFence *pFence) {
66165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
66174a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateFence(device, pCreateInfo, pAllocator, pFence);
66185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6619b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
6620a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        auto &fence_node = dev_data->fenceMap[*pFence];
66218988ad37ea5a054ff2ae3cbe4b767ae6c13cf48bChris Forbes        fence_node.fence = *pFence;
6622a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        fence_node.createInfo = *pCreateInfo;
6623cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes        fence_node.state = (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) ? FENCE_RETIRED : FENCE_UNSIGNALED;
66245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
66255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
66265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
66275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
66285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// TODO handle pipeline caches
662989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreatePipelineCache(VkDevice device, const VkPipelineCacheCreateInfo *pCreateInfo,
663089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                   const VkAllocationCallbacks *pAllocator, VkPipelineCache *pPipelineCache) {
66315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
66324a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreatePipelineCache(device, pCreateInfo, pAllocator, pPipelineCache);
66335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
66345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
66355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6636bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyPipelineCache(VkDevice device, VkPipelineCache pipelineCache,
6637bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkAllocationCallbacks *pAllocator) {
66385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
66394a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.DestroyPipelineCache(device, pipelineCache, pAllocator);
66405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
66415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6642bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL GetPipelineCacheData(VkDevice device, VkPipelineCache pipelineCache, size_t *pDataSize,
6643bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                    void *pData) {
66445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
66454a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.GetPipelineCacheData(device, pipelineCache, pDataSize, pData);
66465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
66475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
66485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6649bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL MergePipelineCaches(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount,
6650bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   const VkPipelineCache *pSrcCaches) {
66515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
66524a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.MergePipelineCaches(device, dstCache, srcCacheCount, pSrcCaches);
66535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
66545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
66555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
66563d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis// utility function to set collective state for pipeline
66574c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisvoid set_pipeline_state(PIPELINE_STATE *pPipe) {
66583d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    // If any attachment used by this pipeline has blendEnable, set top-level blendEnable
66593d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    if (pPipe->graphicsPipelineCI.pColorBlendState) {
66603d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        for (size_t i = 0; i < pPipe->attachments.size(); ++i) {
66613d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis            if (VK_TRUE == pPipe->attachments[i].blendEnable) {
66623d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                if (((pPipe->attachments[i].dstAlphaBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
66633d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                     (pPipe->attachments[i].dstAlphaBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
66643d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                    ((pPipe->attachments[i].dstColorBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
66653d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                     (pPipe->attachments[i].dstColorBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
66663d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                    ((pPipe->attachments[i].srcAlphaBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
66673d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                     (pPipe->attachments[i].srcAlphaBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
66683d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                    ((pPipe->attachments[i].srcColorBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
66693d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                     (pPipe->attachments[i].srcColorBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA))) {
66703d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                    pPipe->blendConstantsEnabled = true;
66713d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                }
66723d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis            }
66733d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        }
66743d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
66753d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis}
66763d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis
667748b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinskistatic bool PreCallCreateGraphicsPipelines(layer_data *device_data, uint32_t count,
667848b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski                                           const VkGraphicsPipelineCreateInfo *create_infos, vector<PIPELINE_STATE *> &pipe_state) {
667948b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski    bool skip = false;
6680bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    instance_layer_data *instance_data =
6681bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        get_my_data_ptr(get_dispatch_key(device_data->instance_data->instance), instance_layer_data_map);
668248b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski
668348b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski    for (uint32_t i = 0; i < count; i++) {
668448b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski        skip |= verifyPipelineCreateState(device_data, pipe_state, i);
668578b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski        if (create_infos[i].pVertexInputState != NULL) {
668678b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski            for (uint32_t j = 0; j < create_infos[i].pVertexInputState->vertexAttributeDescriptionCount; j++) {
668778b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                VkFormat format = create_infos[i].pVertexInputState->pVertexAttributeDescriptions[j].format;
668878b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                // Internal call to get format info.  Still goes through layers, could potentially go directly to ICD.
668978b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                VkFormatProperties properties;
669078b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                instance_data->dispatch_table.GetPhysicalDeviceFormatProperties(device_data->physical_device, format, &properties);
669178b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                if ((properties.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT) == 0) {
669278b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                    skip |= log_msg(
669378b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                        device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
669478b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                        __LINE__, VALIDATION_ERROR_01413, "IMAGE",
669578b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                        "vkCreateGraphicsPipelines: pCreateInfo[%d].pVertexInputState->vertexAttributeDescriptions[%d].format "
669678b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                        "(%s) is not a supported vertex buffer format. %s",
669778b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                        i, j, string_VkFormat(format), validation_error_map[VALIDATION_ERROR_01413]);
669878b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                }
669978b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski            }
670078b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski        }
670148b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski    }
670248b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski    return skip;
670348b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski}
670448b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski
6705bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
6706bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                       const VkGraphicsPipelineCreateInfo *pCreateInfos,
6707bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                       const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) {
67085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO What to do with pipelineCache?
67095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // The order of operations here is a little convoluted but gets the job done
67104c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    //  1. Pipeline create state is first shadowed into PIPELINE_STATE struct
67115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    //  2. Create state is then validated (which uses flags setup during shadowing)
67125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    //  3. If everything looks good, we'll then create the pipeline and add NODE to pipelineMap
671342486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski    bool skip = false;
67145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO : Improve this data struct w/ unique_ptrs so cleanup below is automatic
671542486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski    vector<PIPELINE_STATE *> pipe_state(count);
67165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
67175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
67185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t i = 0;
6719b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
67205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
67215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (i = 0; i < count; i++) {
672242486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski        pipe_state[i] = new PIPELINE_STATE;
672342486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski        pipe_state[i]->initGraphicsPipeline(&pCreateInfos[i]);
672442486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski        pipe_state[i]->render_pass_ci.initialize(getRenderPassState(dev_data, pCreateInfos[i].renderPass)->createInfo.ptr());
672542486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski        pipe_state[i]->pipeline_layout = *getPipelineLayout(dev_data, pCreateInfos[i].layout);
67265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
672742486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski    skip |= PreCallCreateGraphicsPipelines(dev_data, count, pCreateInfos, pipe_state);
67285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6729c70226063be6148056ceeccf835175a1fd59f24fChris Forbes    if (skip) {
6730c70226063be6148056ceeccf835175a1fd59f24fChris Forbes        for (i = 0; i < count; i++) {
6731c70226063be6148056ceeccf835175a1fd59f24fChris Forbes            delete pipe_state[i];
67321ab616b32d4e5b7d62d4a8c41b0c03ea335ab845Chris Forbes            pPipelines[i] = VK_NULL_HANDLE;
6733c70226063be6148056ceeccf835175a1fd59f24fChris Forbes        }
67347a456d188475c23b566334be45dc0489b2789653Chris Forbes        return VK_ERROR_VALIDATION_FAILED_EXT;
67357a456d188475c23b566334be45dc0489b2789653Chris Forbes    }
67367a456d188475c23b566334be45dc0489b2789653Chris Forbes
67377a456d188475c23b566334be45dc0489b2789653Chris Forbes    lock.unlock();
6738bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result =
6739bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        dev_data->dispatch_table.CreateGraphicsPipelines(device, pipelineCache, count, pCreateInfos, pAllocator, pPipelines);
67407a456d188475c23b566334be45dc0489b2789653Chris Forbes    lock.lock();
67417a456d188475c23b566334be45dc0489b2789653Chris Forbes    for (i = 0; i < count; i++) {
674261943a7503bc8594338f3364ef42f1d863486c04Chris Forbes        if (pPipelines[i] == VK_NULL_HANDLE) {
674361943a7503bc8594338f3364ef42f1d863486c04Chris Forbes            delete pipe_state[i];
6744bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        } else {
674561943a7503bc8594338f3364ef42f1d863486c04Chris Forbes            pipe_state[i]->pipeline = pPipelines[i];
674661943a7503bc8594338f3364ef42f1d863486c04Chris Forbes            dev_data->pipelineMap[pipe_state[i]->pipeline] = pipe_state[i];
674761943a7503bc8594338f3364ef42f1d863486c04Chris Forbes        }
67485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6749c70226063be6148056ceeccf835175a1fd59f24fChris Forbes
67505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
67515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
67525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6753bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
6754bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      const VkComputePipelineCreateInfo *pCreateInfos,
6755bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) {
67560108a1af0b7c6949846e9d71d00bbfb322b6f7caChris Forbes    bool skip = false;
67575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
67585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO : Improve this data struct w/ unique_ptrs so cleanup below is automatic
67594c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    vector<PIPELINE_STATE *> pPipeState(count);
67605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
67615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
67625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t i = 0;
6763b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
67645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (i = 0; i < count; i++) {
67655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // TODO: Verify compute stage bits
67665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
67675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Create and initialize internal tracking data structure
67684c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis        pPipeState[i] = new PIPELINE_STATE;
67694c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis        pPipeState[i]->initComputePipeline(&pCreateInfos[i]);
6770c2a5a36d03bbe52f5854a5884346e4a84115e259Tobin Ehlis        pPipeState[i]->pipeline_layout = *getPipelineLayout(dev_data, pCreateInfos[i].layout);
67715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
67725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // TODO: Add Compute Pipeline Verification
67730108a1af0b7c6949846e9d71d00bbfb322b6f7caChris Forbes        skip |= !validate_compute_pipeline(dev_data->report_data, pPipeState[i], &dev_data->enabled_features,
6774bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           dev_data->shaderModuleMap);
67750108a1af0b7c6949846e9d71d00bbfb322b6f7caChris Forbes        // skip |= verifyPipelineCreateState(dev_data, pPipeState[i]);
67765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
67775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
67787a456d188475c23b566334be45dc0489b2789653Chris Forbes    if (skip) {
67795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (i = 0; i < count; i++) {
67805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Clean up any locally allocated data structures
67814c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis            delete pPipeState[i];
6782fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes            pPipelines[i] = VK_NULL_HANDLE;
67835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
67845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return VK_ERROR_VALIDATION_FAILED_EXT;
67855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
67867a456d188475c23b566334be45dc0489b2789653Chris Forbes
67877a456d188475c23b566334be45dc0489b2789653Chris Forbes    lock.unlock();
6788bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result =
6789bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        dev_data->dispatch_table.CreateComputePipelines(device, pipelineCache, count, pCreateInfos, pAllocator, pPipelines);
67907a456d188475c23b566334be45dc0489b2789653Chris Forbes    lock.lock();
67917a456d188475c23b566334be45dc0489b2789653Chris Forbes    for (i = 0; i < count; i++) {
6792fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes        if (pPipelines[i] == VK_NULL_HANDLE) {
6793fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes            delete pPipeState[i];
6794bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        } else {
6795fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes            pPipeState[i]->pipeline = pPipelines[i];
6796fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes            dev_data->pipelineMap[pPipeState[i]->pipeline] = pPipeState[i];
6797fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes        }
67987a456d188475c23b566334be45dc0489b2789653Chris Forbes    }
67997a456d188475c23b566334be45dc0489b2789653Chris Forbes
68005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
68015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
68025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
680389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateSampler(VkDevice device, const VkSamplerCreateInfo *pCreateInfo,
680489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                             const VkAllocationCallbacks *pAllocator, VkSampler *pSampler) {
68055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
68064a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateSampler(device, pCreateInfo, pAllocator, pSampler);
68075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6808b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
6809d31a44af6da568692a73201825459689c9431867Tobin Ehlis        dev_data->samplerMap[*pSampler] = unique_ptr<SAMPLER_STATE>(new SAMPLER_STATE(pSampler, pCreateInfo));
68105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
68115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
68125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
68135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
68140c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlisstatic bool PreCallValidateCreateDescriptorSetLayout(layer_data *dev_data, const VkDescriptorSetLayoutCreateInfo *create_info) {
6815cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.create_descriptor_set_layout) return false;
68160c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    return cvdescriptorset::DescriptorSetLayout::ValidateCreateInfo(dev_data->report_data, create_info);
68170c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis}
68180c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis
68190c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlisstatic void PostCallRecordCreateDescriptorSetLayout(layer_data *dev_data, const VkDescriptorSetLayoutCreateInfo *create_info,
68200c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis                                                    VkDescriptorSetLayout set_layout) {
68213f1d2ba6852cf6b1bb4e1f06d690293565108e2cTobin Ehlis    // TODO: Convert this to unique_ptr to avoid leaks
68220c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    dev_data->descriptorSetLayoutMap[set_layout] = new cvdescriptorset::DescriptorSetLayout(create_info, set_layout);
68230c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis}
68240c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis
6825bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
6826bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                         const VkAllocationCallbacks *pAllocator,
6827bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                         VkDescriptorSetLayout *pSetLayout) {
68285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
68290c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
68300c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
68310c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    bool skip = PreCallValidateCreateDescriptorSetLayout(dev_data, pCreateInfo);
68320c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    if (!skip) {
68330c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis        lock.unlock();
68340c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis        result = dev_data->dispatch_table.CreateDescriptorSetLayout(device, pCreateInfo, pAllocator, pSetLayout);
68350c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis        if (VK_SUCCESS == result) {
68360c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis            lock.lock();
68370c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis            PostCallRecordCreateDescriptorSetLayout(dev_data, pCreateInfo, *pSetLayout);
68380c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis        }
68395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
68405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
68415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
68425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
68439e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz// Used by CreatePipelineLayout and CmdPushConstants.
68449e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz// Note that the index argument is optional and only used by CreatePipelineLayout.
68459e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultzstatic bool validatePushConstantRange(const layer_data *dev_data, const uint32_t offset, const uint32_t size,
68469e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz                                      const char *caller_name, uint32_t index = 0) {
6847cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.push_constant_range) return false;
68489e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    uint32_t const maxPushConstantsSize = dev_data->phys_dev_properties.properties.limits.maxPushConstantsSize;
684983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
68509e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // Check that offset + size don't exceed the max.
68519e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // Prevent arithetic overflow here by avoiding addition and testing in this order.
68529e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    if ((offset >= maxPushConstantsSize) || (size > maxPushConstantsSize - offset)) {
68539e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        // 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.
68549e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        if (0 == strcmp(caller_name, "vkCreatePipelineLayout()")) {
6855e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis            if (offset >= maxPushConstantsSize) {
6856e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis                skip_call |=
6857e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
6858cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            VALIDATION_ERROR_00877, "DS",
6859cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s call has push constants index %u with offset %u that "
6860cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "exceeds this device's maxPushConstantSize of %u. %s",
6861e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis                            caller_name, index, offset, maxPushConstantsSize, validation_error_map[VALIDATION_ERROR_00877]);
6862e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis            }
6863e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis            if (size > maxPushConstantsSize - offset) {
6864e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis                skip_call |=
6865e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
6866cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            VALIDATION_ERROR_00880, "DS",
6867cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s call has push constants index %u with offset %u and size %u that "
6868cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "exceeds this device's maxPushConstantSize of %u. %s",
6869e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis                            caller_name, index, offset, size, maxPushConstantsSize, validation_error_map[VALIDATION_ERROR_00880]);
6870e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis            }
68719e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else if (0 == strcmp(caller_name, "vkCmdPushConstants()")) {
68724527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            if (offset >= maxPushConstantsSize) {
68734527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                skip_call |=
68744527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
6875cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            VALIDATION_ERROR_00991, "DS",
6876cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s call has push constants index %u with offset %u that "
6877cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "exceeds this device's maxPushConstantSize of %u. %s",
68784527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            caller_name, index, offset, maxPushConstantsSize, validation_error_map[VALIDATION_ERROR_00991]);
68794527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            }
68804527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            if (size > maxPushConstantsSize - offset) {
68814527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                skip_call |=
68824527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
6883cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            VALIDATION_ERROR_00992, "DS",
6884cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s call has push constants index %u with offset %u and size %u that "
6885cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "exceeds this device's maxPushConstantSize of %u. %s",
68864527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            caller_name, index, offset, size, maxPushConstantsSize, validation_error_map[VALIDATION_ERROR_00992]);
68874527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            }
68889e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else {
688983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
689083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 DRAWSTATE_INTERNAL_ERROR, "DS", "%s caller not supported.", caller_name);
68919e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
68929e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    }
68939e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // size needs to be non-zero and a multiple of 4.
68949e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    if ((size == 0) || ((size & 0x3) != 0)) {
68959e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        if (0 == strcmp(caller_name, "vkCreatePipelineLayout()")) {
6896891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis            if (size == 0) {
6897891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
6898cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     __LINE__, VALIDATION_ERROR_00878, "DS",
6899cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "%s call has push constants index %u with "
6900cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "size %u. Size must be greater than zero. %s",
6901891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis                                     caller_name, index, size, validation_error_map[VALIDATION_ERROR_00878]);
6902891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis            }
6903891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis            if (size & 0x3) {
6904891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
6905cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     __LINE__, VALIDATION_ERROR_00879, "DS",
6906cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "%s call has push constants index %u with "
6907cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "size %u. Size must be a multiple of 4. %s",
6908891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis                                     caller_name, index, size, validation_error_map[VALIDATION_ERROR_00879]);
6909891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis            }
69109e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else if (0 == strcmp(caller_name, "vkCmdPushConstants()")) {
69114527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            if (size == 0) {
69124527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
6913cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     __LINE__, VALIDATION_ERROR_01000, "DS",
6914cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "%s call has push constants index %u with "
6915cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "size %u. Size must be greater than zero. %s",
69164527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                     caller_name, index, size, validation_error_map[VALIDATION_ERROR_01000]);
69174527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            }
69184527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            if (size & 0x3) {
69194527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
6920cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     __LINE__, VALIDATION_ERROR_00990, "DS",
6921cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "%s call has push constants index %u with "
6922cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "size %u. Size must be a multiple of 4. %s",
69234527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                     caller_name, index, size, validation_error_map[VALIDATION_ERROR_00990]);
69244527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            }
69259e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else {
692683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
692783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 DRAWSTATE_INTERNAL_ERROR, "DS", "%s caller not supported.", caller_name);
69289e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
69299e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    }
69309e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // offset needs to be a multiple of 4.
69319e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    if ((offset & 0x3) != 0) {
69329e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        if (0 == strcmp(caller_name, "vkCreatePipelineLayout()")) {
693383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
6934cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 VALIDATION_ERROR_02521, "DS",
6935cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "%s call has push constants index %u with "
6936cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "offset %u. Offset must be a multiple of 4. %s",
69374527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 caller_name, index, offset, validation_error_map[VALIDATION_ERROR_02521]);
69389e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else if (0 == strcmp(caller_name, "vkCmdPushConstants()")) {
693983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
6940cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 VALIDATION_ERROR_00989, "DS",
6941cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "%s call has push constants with "
6942cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "offset %u. Offset must be a multiple of 4. %s",
69434527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 caller_name, offset, validation_error_map[VALIDATION_ERROR_00989]);
69449e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else {
694583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
694683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 DRAWSTATE_INTERNAL_ERROR, "DS", "%s caller not supported.", caller_name);
69479e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
69485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
694983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
69505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
69515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6952bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo *pCreateInfo,
695389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                    const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout) {
695483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
69555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
69561c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis    // TODO : Add checks for VALIDATION_ERRORS 865-871
69579e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // Push Constant Range checks
695807a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz    uint32_t i, j;
69595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
696083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis        skip_call |= validatePushConstantRange(dev_data, pCreateInfo->pPushConstantRanges[i].offset,
696183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                               pCreateInfo->pPushConstantRanges[i].size, "vkCreatePipelineLayout()", i);
69629e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        if (0 == pCreateInfo->pPushConstantRanges[i].stageFlags) {
696383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
69644527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 VALIDATION_ERROR_00882, "DS", "vkCreatePipelineLayout() call has no stageFlags set. %s",
69654527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 validation_error_map[VALIDATION_ERROR_00882]);
69669e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
69679e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    }
6968cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
696907a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz
69709e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // Each range has been validated.  Now check for overlap between ranges (if they are good).
697107a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz    // There's no explicit Valid Usage language against this, so issue a warning instead of an error.
697207a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz    for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
697307a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz        for (j = i + 1; j < pCreateInfo->pushConstantRangeCount; ++j) {
697407a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz            const uint32_t minA = pCreateInfo->pPushConstantRanges[i].offset;
697507a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz            const uint32_t maxA = minA + pCreateInfo->pPushConstantRanges[i].size;
697607a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz            const uint32_t minB = pCreateInfo->pPushConstantRanges[j].offset;
697707a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz            const uint32_t maxB = minB + pCreateInfo->pPushConstantRanges[j].size;
697807a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz            if ((minA <= minB && maxA > minB) || (minB <= minA && maxB > minA)) {
6979cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
6980cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     __LINE__, DRAWSTATE_PUSH_CONSTANTS_ERROR, "DS",
6981cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "vkCreatePipelineLayout() call has push constants with "
6982cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "overlapping ranges: %u:[%u, %u), %u:[%u, %u)",
6983cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     i, minA, maxA, j, minB, maxB);
69849e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz            }
69855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
69865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6987f73b2046273413ea1338dd714d67c39f8e0fa09eChris Forbes
69884a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreatePipelineLayout(device, pCreateInfo, pAllocator, pPipelineLayout);
69895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6990b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
69915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        PIPELINE_LAYOUT_NODE &plNode = dev_data->pipelineLayoutMap[*pPipelineLayout];
699269b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis        plNode.layout = *pPipelineLayout;
6993416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis        plNode.set_layouts.resize(pCreateInfo->setLayoutCount);
69945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (i = 0; i < pCreateInfo->setLayoutCount; ++i) {
6995416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis            plNode.set_layouts[i] = getDescriptorSetLayout(dev_data, pCreateInfo->pSetLayouts[i]);
69965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6997416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis        plNode.push_constant_ranges.resize(pCreateInfo->pushConstantRangeCount);
69985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
6999416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis            plNode.push_constant_ranges[i] = pCreateInfo->pPushConstantRanges[i];
70005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
70015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
70025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
70035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
70045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7005bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateDescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo *pCreateInfo,
7006bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                    const VkAllocationCallbacks *pAllocator, VkDescriptorPool *pDescriptorPool) {
70075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
70084a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateDescriptorPool(device, pCreateInfo, pAllocator, pDescriptorPool);
70095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
70105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
7011414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                    (uint64_t)*pDescriptorPool, __LINE__, DRAWSTATE_OUT_OF_MEMORY, "DS", "Created Descriptor Pool 0x%" PRIxLEAST64,
70125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    (uint64_t)*pDescriptorPool))
70135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return VK_ERROR_VALIDATION_FAILED_EXT;
7014a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis        DESCRIPTOR_POOL_STATE *pNewNode = new DESCRIPTOR_POOL_STATE(*pDescriptorPool, pCreateInfo);
70155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (NULL == pNewNode) {
70165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
70175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        (uint64_t)*pDescriptorPool, __LINE__, DRAWSTATE_OUT_OF_MEMORY, "DS",
7018a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis                        "Out of memory while attempting to allocate DESCRIPTOR_POOL_STATE in vkCreateDescriptorPool()"))
70195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return VK_ERROR_VALIDATION_FAILED_EXT;
70205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
7021b9e992386a44404152747d66817a733aa127e281Jeremy Hayes            std::lock_guard<std::mutex> lock(global_lock);
70225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->descriptorPoolMap[*pDescriptorPool] = pNewNode;
70235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
70245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
70255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Need to do anything if pool create fails?
70265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
70275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
70285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
70295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7030bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL ResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool,
7031bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   VkDescriptorPoolResetFlags flags) {
70327286e20c06011d3c6fa7edfbdbadd42bb6e8cc35Tobin Ehlis    // TODO : Add checks for VALIDATION_ERROR_00928
70335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
70344a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.ResetDescriptorPool(device, descriptorPool, flags);
70355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
7036b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
70375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        clearDescriptorPool(dev_data, device, descriptorPool, flags);
70385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
70395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
70405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
70412c4e180a4442f968b44f3d5136f7ffda706f6428Chris Forbes// Ensure the pool contains enough descriptors and descriptor sets to satisfy
7042789832b514862c7a7b5b847eeb8e7cacb733b77bTobin Ehlis// an allocation request. Fills common_data with the total number of descriptors of each type required,
7043789832b514862c7a7b5b847eeb8e7cacb733b77bTobin Ehlis// as well as DescriptorSetLayout ptrs used for later update.
70447f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlisstatic bool PreCallValidateAllocateDescriptorSets(layer_data *dev_data, const VkDescriptorSetAllocateInfo *pAllocateInfo,
70457f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis                                                  cvdescriptorset::AllocateDescriptorSetsData *common_data) {
7046cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.allocate_descriptor_sets) return false;
70477e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlis    // All state checks for AllocateDescriptorSets is done in single function
7048e3f7c45fd64a44a67ce96c89e2bbee426c6ecf24Tobin Ehlis    return cvdescriptorset::ValidateAllocateDescriptorSets(dev_data->report_data, pAllocateInfo, dev_data, common_data);
70497e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlis}
70507e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlis// Allocation state was good and call down chain was made so update state based on allocating descriptor sets
70517e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlisstatic void PostCallRecordAllocateDescriptorSets(layer_data *dev_data, const VkDescriptorSetAllocateInfo *pAllocateInfo,
70527f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis                                                 VkDescriptorSet *pDescriptorSets,
70537f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis                                                 const cvdescriptorset::AllocateDescriptorSetsData *common_data) {
70547e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlis    // All the updates are contained in a single cvdescriptorset function
70552c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    cvdescriptorset::PerformAllocateDescriptorSets(pAllocateInfo, pDescriptorSets, common_data, &dev_data->descriptorPoolMap,
7056b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis                                                   &dev_data->setMap, dev_data);
70572c4e180a4442f968b44f3d5136f7ffda706f6428Chris Forbes}
70582c4e180a4442f968b44f3d5136f7ffda706f6428Chris Forbes
7059bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL AllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo,
7060bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      VkDescriptorSet *pDescriptorSets) {
70615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
7062b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
70637f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis    cvdescriptorset::AllocateDescriptorSetsData common_data(pAllocateInfo->descriptorSetCount);
70647f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis    bool skip_call = PreCallValidateAllocateDescriptorSets(dev_data, pAllocateInfo, &common_data);
7065b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7066d173e0daab123373ce75105f2a908f6ae7cef6abChris Forbes
7067cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
7068d173e0daab123373ce75105f2a908f6ae7cef6abChris Forbes
70694a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.AllocateDescriptorSets(device, pAllocateInfo, pDescriptorSets);
70706511ce241f7f210211e0c0e882f3c14889071f4dChris Forbes
70715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
7072b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
70737f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis        PostCallRecordAllocateDescriptorSets(dev_data, pAllocateInfo, pDescriptorSets, &common_data);
7074b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
70755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
70765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
70775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
7078cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis// Verify state before freeing DescriptorSets
7079cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlisstatic bool PreCallValidateFreeDescriptorSets(const layer_data *dev_data, VkDescriptorPool pool, uint32_t count,
7080cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis                                              const VkDescriptorSet *descriptor_sets) {
7081cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.free_descriptor_sets) return false;
7082cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    bool skip_call = false;
7083cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    // First make sure sets being destroyed are not currently in-use
7084cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    for (uint32_t i = 0; i < count; ++i)
7085cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis        skip_call |= validateIdleDescriptorSet(dev_data, descriptor_sets[i], "vkFreeDescriptorSets");
7086cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis
7087a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis    DESCRIPTOR_POOL_STATE *pool_state = getDescriptorPoolState(dev_data, pool);
7088a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis    if (pool_state && !(VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT & pool_state->createInfo.flags)) {
7089cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis        // Can't Free from a NON_FREE pool
7090cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
70911c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis                             reinterpret_cast<uint64_t &>(pool), __LINE__, VALIDATION_ERROR_00922, "DS",
7092cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis                             "It is invalid to call vkFreeDescriptorSets() with a pool created without setting "
70931c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis                             "VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT. %s",
70941c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis                             validation_error_map[VALIDATION_ERROR_00922]);
7095cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    }
7096cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    return skip_call;
7097cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis}
7098cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis// Sets have been removed from the pool so update underlying state
7099cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlisstatic void PostCallRecordFreeDescriptorSets(layer_data *dev_data, VkDescriptorPool pool, uint32_t count,
7100cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis                                             const VkDescriptorSet *descriptor_sets) {
7101a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis    DESCRIPTOR_POOL_STATE *pool_state = getDescriptorPoolState(dev_data, pool);
7102cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    // Update available descriptor sets in pool
7103cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    pool_state->availableSets += count;
7104cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis
7105cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    // For each freed descriptor add its resources back into the pool as available and remove from pool and setMap
7106cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    for (uint32_t i = 0; i < count; ++i) {
71071c130ea631a82716dc7334de17767536525f2292Tobin Ehlis        auto descriptor_set = dev_data->setMap[descriptor_sets[i]];
7108cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis        uint32_t type_index = 0, descriptor_count = 0;
71091c130ea631a82716dc7334de17767536525f2292Tobin Ehlis        for (uint32_t j = 0; j < descriptor_set->GetBindingCount(); ++j) {
71101c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            type_index = static_cast<uint32_t>(descriptor_set->GetTypeFromIndex(j));
71111c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            descriptor_count = descriptor_set->GetDescriptorCountFromIndex(j);
7112cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis            pool_state->availableDescriptorTypeCount[type_index] += descriptor_count;
7113cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis        }
71141c130ea631a82716dc7334de17767536525f2292Tobin Ehlis        freeDescriptorSet(dev_data, descriptor_set);
71151c130ea631a82716dc7334de17767536525f2292Tobin Ehlis        pool_state->sets.erase(descriptor_set);
7116cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    }
7117cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis}
71185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7119bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL FreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t count,
7120bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                  const VkDescriptorSet *pDescriptorSets) {
71215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
71225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Make sure that no sets being destroyed are in-flight
7123b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
712483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = PreCallValidateFreeDescriptorSets(dev_data, descriptorPool, count, pDescriptorSets);
7125b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7126e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis
7127cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
71284a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.FreeDescriptorSets(device, descriptorPool, count, pDescriptorSets);
71295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
7130b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
7131cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis        PostCallRecordFreeDescriptorSets(dev_data, descriptorPool, count, pDescriptorSets);
7132b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
71335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
71345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
71355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
71366b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis// TODO : This is a Proof-of-concept for core validation architecture
71376b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis//  Really we'll want to break out these functions to separate files but
71386b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis//  keeping it all together here to prove out design
71396b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis// PreCallValidate* handles validating all of the state prior to calling down chain to UpdateDescriptorSets()
71406b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlisstatic bool PreCallValidateUpdateDescriptorSets(layer_data *dev_data, uint32_t descriptorWriteCount,
71416b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                                const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
71426b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                                const VkCopyDescriptorSet *pDescriptorCopies) {
7143cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.update_descriptor_sets) return false;
71446b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // First thing to do is perform map look-ups.
71456b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // NOTE : UpdateDescriptorSets is somewhat unique in that it's operating on a number of DescriptorSets
71466b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    //  so we can't just do a single map look-up up-front, but do them individually in functions below
71476b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis
71486b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // Now make call(s) that validate state, but don't perform state updates in this function
71496b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // Note, here DescriptorSets is unique in that we don't yet have an instance. Using a helper function in the
71506b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    //  namespace which will parse params and make calls into specific class instances
7151104ab082916e41467ef60baaab7a5a8b2e02c59cTobin Ehlis    return cvdescriptorset::ValidateUpdateDescriptorSets(dev_data->report_data, dev_data, descriptorWriteCount, pDescriptorWrites,
7152104ab082916e41467ef60baaab7a5a8b2e02c59cTobin Ehlis                                                         descriptorCopyCount, pDescriptorCopies);
71536b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis}
71546b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis// PostCallRecord* handles recording state updates following call down chain to UpdateDescriptorSets()
71556b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlisstatic void PostCallRecordUpdateDescriptorSets(layer_data *dev_data, uint32_t descriptorWriteCount,
71566b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                               const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
71576b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                               const VkCopyDescriptorSet *pDescriptorCopies) {
7158104ab082916e41467ef60baaab7a5a8b2e02c59cTobin Ehlis    cvdescriptorset::PerformUpdateDescriptorSets(dev_data, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
71596b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                                 pDescriptorCopies);
71606b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis}
71615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7162bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL UpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount,
7163bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
7164bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkCopyDescriptorSet *pDescriptorCopies) {
71656b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // Only map look-up at top level is for device-level layer_data
71665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
7167b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
71686b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    bool skip_call = PreCallValidateUpdateDescriptorSets(dev_data, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
71696b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                                         pDescriptorCopies);
7170b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
71716b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    if (!skip_call) {
71724a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.UpdateDescriptorSets(device, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
71734a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                      pDescriptorCopies);
71746b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis        lock.lock();
71756b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis        // Since UpdateDescriptorSets() is void, nothing to check prior to updating state
71766b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis        PostCallRecordUpdateDescriptorSets(dev_data, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
71776b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                           pDescriptorCopies);
71785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
71795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
71805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7181bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL AllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pCreateInfo,
7182bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      VkCommandBuffer *pCommandBuffer) {
71835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
71844a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.AllocateCommandBuffers(device, pCreateInfo, pCommandBuffer);
71855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
7186b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::unique_lock<std::mutex> lock(global_lock);
7187cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes        auto pPool = getCommandPoolNode(dev_data, pCreateInfo->commandPool);
7188cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes
7189cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes        if (pPool) {
719072d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis            for (uint32_t i = 0; i < pCreateInfo->commandBufferCount; i++) {
71915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // Add command buffer to its commandPool map
7192cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes                pPool->commandBuffers.push_back(pCommandBuffer[i]);
71935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                GLOBAL_CB_NODE *pCB = new GLOBAL_CB_NODE;
71945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // Add command buffer to map
71955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                dev_data->commandBufferMap[pCommandBuffer[i]] = pCB;
71965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                resetCB(dev_data, pCommandBuffer[i]);
71975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pCB->createInfo = *pCreateInfo;
71985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pCB->device = device;
71995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
72005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7201b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
72025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
72035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
72045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
72055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7206883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis// Add bindings between the given cmd buffer & framebuffer and the framebuffer's children
7207c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlisstatic void AddFramebufferBinding(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, FRAMEBUFFER_STATE *fb_state) {
72080245b74a083d2cb3b083571deb0fe13b4ab428a4Tobin Ehlis    addCommandBufferBinding(&fb_state->cb_bindings,
72090245b74a083d2cb3b083571deb0fe13b4ab428a4Tobin Ehlis                            {reinterpret_cast<uint64_t &>(fb_state->framebuffer), VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT},
72100245b74a083d2cb3b083571deb0fe13b4ab428a4Tobin Ehlis                            cb_state);
7211883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis    for (auto attachment : fb_state->attachments) {
7212883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        auto view_state = attachment.view_state;
7213883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        if (view_state) {
721403ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis            AddCommandBufferBindingImageView(dev_data, cb_state, view_state);
7215883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        }
7216127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis        auto rp_state = getRenderPassState(dev_data, fb_state->createInfo.renderPass);
7217883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        if (rp_state) {
7218883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis            addCommandBufferBinding(
7219883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis                &rp_state->cb_bindings,
7220883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis                {reinterpret_cast<uint64_t &>(rp_state->renderPass), VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT}, cb_state);
7221883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        }
7222883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis    }
7223883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis}
7224883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis
7225bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL BeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo) {
722683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
72275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
7228b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
72295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Validate command buffer level
7230f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis    GLOBAL_CB_NODE *cb_node = getCBNode(dev_data, commandBuffer);
7231f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis    if (cb_node) {
72325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // This implicitly resets the Cmd Buffer so make sure any fence is done and then clear memory references
7233a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        if (dev_data->globalInFlightCmdBuffers.count(commandBuffer)) {
723483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |=
7235a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
72364527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                        (uint64_t)commandBuffer, __LINE__, VALIDATION_ERROR_00104, "MEM",
7237d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen                        "Calling vkBeginCommandBuffer() on active command buffer 0x%p before it has completed. "
72384527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                        "You must check command buffer fence before this call. %s",
72394527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                        commandBuffer, validation_error_map[VALIDATION_ERROR_00104]);
72405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7241f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        clear_cmd_buf_and_mem_references(dev_data, cb_node);
7242f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        if (cb_node->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
72435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Secondary Command Buffer
72445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            const VkCommandBufferInheritanceInfo *pInfo = pBeginInfo->pInheritanceInfo;
72455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!pInfo) {
724683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                skip_call |=
72475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
72484527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            reinterpret_cast<uint64_t>(commandBuffer), __LINE__, VALIDATION_ERROR_00106, "DS",
7249bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "vkBeginCommandBuffer(): Secondary Command Buffer (0x%p) must have inheritance info. %s", commandBuffer,
7250bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            validation_error_map[VALIDATION_ERROR_00106]);
72515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else {
72525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (pBeginInfo->flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT) {
72532c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                    // Object_tracker makes sure these objects are valid
72542c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                    assert(pInfo->renderPass);
72552c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                    assert(pInfo->framebuffer);
72562c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                    string errorString = "";
72572c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                    auto framebuffer = getFramebufferState(dev_data, pInfo->framebuffer);
72582c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                    if (framebuffer) {
72592c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                        if ((framebuffer->createInfo.renderPass != pInfo->renderPass) &&
72602c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                            !verify_renderpass_compatibility(dev_data, framebuffer->renderPassCreateInfo.ptr(),
72612c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                             getRenderPassState(dev_data, pInfo->renderPass)->createInfo.ptr(),
72622c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                             errorString)) {
72632c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                            // renderPass that framebuffer was created with must be compatible with local renderPass
72642c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
72652c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
72662c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                 reinterpret_cast<uint64_t>(commandBuffer), __LINE__, VALIDATION_ERROR_00112, "DS",
72672c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                 "vkBeginCommandBuffer(): Secondary Command "
7268cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                 "Buffer (0x%p) renderPass (0x%" PRIxLEAST64
7269cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                 ") is incompatible w/ framebuffer "
72702c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                 "(0x%" PRIxLEAST64 ") w/ render pass (0x%" PRIxLEAST64 ") due to: %s. %s",
72712c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                 commandBuffer, reinterpret_cast<const uint64_t &>(pInfo->renderPass),
72722c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                 reinterpret_cast<const uint64_t &>(pInfo->framebuffer),
72732c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                 reinterpret_cast<uint64_t &>(framebuffer->createInfo.renderPass),
72742c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                 errorString.c_str(), validation_error_map[VALIDATION_ERROR_00112]);
72755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        }
72762c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                        // Connect this framebuffer and its children to this cmdBuffer
72772c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                        AddFramebufferBinding(dev_data, cb_node, framebuffer);
72785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
72795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
72804527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                if ((pInfo->occlusionQueryEnable == VK_FALSE || dev_data->enabled_features.occlusionQueryPrecise == VK_FALSE) &&
72815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    (pInfo->queryFlags & VK_QUERY_CONTROL_PRECISE_BIT)) {
728283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
728383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                         VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t>(commandBuffer),
72844527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                         __LINE__, VALIDATION_ERROR_00107, "DS",
728583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                         "vkBeginCommandBuffer(): Secondary Command Buffer (0x%p) must not have "
728683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                         "VK_QUERY_CONTROL_PRECISE_BIT if occulusionQuery is disabled or the device does not "
72874527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                         "support precise occlusion queries. %s",
72884527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                         commandBuffer, validation_error_map[VALIDATION_ERROR_00107]);
72895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
72905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
72915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (pInfo && pInfo->renderPass != VK_NULL_HANDLE) {
7292127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                auto renderPass = getRenderPassState(dev_data, pInfo->renderPass);
729316387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                if (renderPass) {
7294fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes                    if (pInfo->subpass >= renderPass->createInfo.subpassCount) {
729583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                        skip_call |= log_msg(
7296bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
7297bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            (uint64_t)commandBuffer, __LINE__, VALIDATION_ERROR_00111, "DS",
72984527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            "vkBeginCommandBuffer(): Secondary Command Buffers (0x%p) must have a subpass index (%d) "
72994527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            "that is less than the number of subpasses (%d). %s",
73004527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            commandBuffer, pInfo->subpass, renderPass->createInfo.subpassCount,
73014527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            validation_error_map[VALIDATION_ERROR_00111]);
73025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
73035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
73045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
73055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7306f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        if (CB_RECORDING == cb_node->state) {
7307cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            skip_call |=
7308cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
7309cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        (uint64_t)commandBuffer, __LINE__, VALIDATION_ERROR_00103, "DS",
7310cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "vkBeginCommandBuffer(): Cannot call Begin on command buffer (0x%p"
7311cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        ") in the RECORDING state. Must first call vkEndCommandBuffer(). %s",
7312cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        commandBuffer, validation_error_map[VALIDATION_ERROR_00103]);
7313347d4d3139a1e743ed85bd375c20fd35bbe68d74Chris Forbes        } else if (CB_RECORDED == cb_node->state || (CB_INVALID == cb_node->state && CMD_END == cb_node->last_cmd)) {
7314f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            VkCommandPool cmdPool = cb_node->createInfo.commandPool;
7315cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes            auto pPool = getCommandPoolNode(dev_data, cmdPool);
7316cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes            if (!(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT & pPool->createFlags)) {
731783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                skip_call |=
73185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
73194527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            (uint64_t)commandBuffer, __LINE__, VALIDATION_ERROR_00105, "DS",
7320226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                            "Call to vkBeginCommandBuffer() on command buffer (0x%p"
7321414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                            ") attempts to implicitly reset cmdBuffer created from command pool (0x%" PRIxLEAST64
73224527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            ") that does NOT have the VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT bit set. %s",
73234527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            commandBuffer, (uint64_t)cmdPool, validation_error_map[VALIDATION_ERROR_00105]);
73245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
73255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            resetCB(dev_data, commandBuffer);
73265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
73275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Set updated state here in case implicit reset occurs above
7328f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        cb_node->state = CB_RECORDING;
7329f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        cb_node->beginInfo = *pBeginInfo;
7330f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        if (cb_node->beginInfo.pInheritanceInfo) {
7331f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->inheritanceInfo = *(cb_node->beginInfo.pInheritanceInfo);
7332f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->beginInfo.pInheritanceInfo = &cb_node->inheritanceInfo;
7333888e1d268098177fde4a2263e3d7b7cc415f1debMark Young            // If we are a secondary command-buffer and inheriting.  Update the items we should inherit.
7334f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            if ((cb_node->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) &&
7335f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                (cb_node->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
7336127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                cb_node->activeRenderPass = getRenderPassState(dev_data, cb_node->beginInfo.pInheritanceInfo->renderPass);
7337f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                cb_node->activeSubpass = cb_node->beginInfo.pInheritanceInfo->subpass;
7338350841afb70bf8dcfc3c6ec6b66f0aaa639553a3Tobin Ehlis                cb_node->activeFramebuffer = cb_node->beginInfo.pInheritanceInfo->framebuffer;
7339f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                cb_node->framebuffers.insert(cb_node->beginInfo.pInheritanceInfo->framebuffer);
7340888e1d268098177fde4a2263e3d7b7cc415f1debMark Young            }
73415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
73425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7343b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
734483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (skip_call) {
73455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return VK_ERROR_VALIDATION_FAILED_EXT;
73465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
73474a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.BeginCommandBuffer(commandBuffer, pBeginInfo);
7348400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis
73495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
73505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
73515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
735289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL EndCommandBuffer(VkCommandBuffer commandBuffer) {
735383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
73545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_SUCCESS;
73555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
7356b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
73575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
73585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
73594527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton        if ((VK_COMMAND_BUFFER_LEVEL_PRIMARY == pCB->createInfo.level) ||
73604527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
7361fd61966f8d41b5bce15620b70563b7864cbb28feCody Northrop            // This needs spec clarification to update valid usage, see comments in PR:
7362fd61966f8d41b5bce15620b70563b7864cbb28feCody Northrop            // https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/pull/516#discussion_r63013756
7363ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen            skip_call |= insideRenderPass(dev_data, pCB, "vkEndCommandBuffer()", VALIDATION_ERROR_00123);
7364fd61966f8d41b5bce15620b70563b7864cbb28feCody Northrop        }
736529f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_END, "vkEndCommandBuffer()");
736629f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        UpdateCmdBufferLastCmd(dev_data, pCB, CMD_END);
73675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto query : pCB->activeQueries) {
736883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
73694527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 VALIDATION_ERROR_00124, "DS",
73704527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 "Ending command buffer with in progress query: queryPool 0x%" PRIx64 ", index %d. %s",
73714527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 (uint64_t)(query.pool), query.index, validation_error_map[VALIDATION_ERROR_00124]);
73725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
73735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
737483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (!skip_call) {
7375b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
73764a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.EndCommandBuffer(commandBuffer);
7377b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
73785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (VK_SUCCESS == result) {
73795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pCB->state = CB_RECORDED;
73805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Reset CB status flags
73815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pCB->status = 0;
73825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
73835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
73845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        result = VK_ERROR_VALIDATION_FAILED_EXT;
73855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7386b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
73875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
73885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
73895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7390bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL ResetCommandBuffer(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags) {
7391bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    bool skip_call = false;
73925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
7393b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
73945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
73955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkCommandPool cmdPool = pCB->createInfo.commandPool;
7396cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes    auto pPool = getCommandPoolNode(dev_data, cmdPool);
7397cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes    if (!(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT & pPool->createFlags)) {
7398bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
73994527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                             (uint64_t)commandBuffer, __LINE__, VALIDATION_ERROR_00093, "DS",
7400226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                             "Attempt to reset command buffer (0x%p) created from command pool (0x%" PRIxLEAST64
74014527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                             ") that does NOT have the VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT bit set. %s",
74024527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                             commandBuffer, (uint64_t)cmdPool, validation_error_map[VALIDATION_ERROR_00093]);
74035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7404cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis    skip_call |= checkCommandBufferInFlight(dev_data, pCB, "reset", VALIDATION_ERROR_00092);
7405b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7406cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
74074a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.ResetCommandBuffer(commandBuffer, flags);
74085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
7409b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
7410a964cad279f9749cd9ebfc7555247ff3bff26d53Chris Forbes        dev_data->globalInFlightCmdBuffers.erase(commandBuffer);
74115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        resetCB(dev_data, commandBuffer);
7412b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
74135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
74145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
74155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
741693c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski
7417bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBindPipeline(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
7418bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           VkPipeline pipeline) {
7419e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis    bool skip = false;
74205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
7421b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7422e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis    GLOBAL_CB_NODE *cb_state = getCBNode(dev_data, commandBuffer);
7423e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis    if (cb_state) {
742429f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip |= ValidateCmd(dev_data, cb_state, CMD_BINDPIPELINE, "vkCmdBindPipeline()");
742529f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        UpdateCmdBufferLastCmd(dev_data, cb_state, CMD_BINDPIPELINE);
7426e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        if ((VK_PIPELINE_BIND_POINT_COMPUTE == pipelineBindPoint) && (cb_state->activeRenderPass)) {
7427e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            skip |=
74285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
74295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        (uint64_t)pipeline, __LINE__, DRAWSTATE_INVALID_RENDERPASS_CMD, "DS",
7430414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                        "Incorrectly binding compute pipeline (0x%" PRIxLEAST64 ") during active RenderPass (0x%" PRIxLEAST64 ")",
7431e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis                        (uint64_t)pipeline, (uint64_t)cb_state->activeRenderPass->renderPass);
74325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
74334527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton        // TODO: VALIDATION_ERROR_00594 VALIDATION_ERROR_00596
74345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7435e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        PIPELINE_STATE *pipe_state = getPipelineState(dev_data, pipeline);
7436e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        if (pipe_state) {
7437e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            cb_state->lastBound[pipelineBindPoint].pipeline_state = pipe_state;
7438e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            set_cb_pso_status(cb_state, pipe_state);
7439e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            set_pipeline_state(pipe_state);
74405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
7441e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
74424527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            (uint64_t)pipeline, __LINE__, VALIDATION_ERROR_00600, "DS",
74434527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            "Attempt to bind Pipeline 0x%" PRIxLEAST64 " that doesn't exist! %s", (uint64_t)(pipeline),
74444527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            validation_error_map[VALIDATION_ERROR_00600]);
7445e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        }
7446e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        addCommandBufferBinding(&pipe_state->cb_bindings,
7447e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis                                {reinterpret_cast<uint64_t &>(pipeline), VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT}, cb_state);
7448e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        if (VK_PIPELINE_BIND_POINT_GRAPHICS == pipelineBindPoint) {
7449e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            // Add binding for child renderpass
7450e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            auto rp_state = getRenderPassState(dev_data, pipe_state->graphicsPipelineCI.renderPass);
7451e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            if (rp_state) {
7452e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis                addCommandBufferBinding(
7453e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis                    &rp_state->cb_bindings,
7454e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis                    {reinterpret_cast<uint64_t &>(rp_state->renderPass), VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT}, cb_state);
7455e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            }
74565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
74575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7458b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7459cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdBindPipeline(commandBuffer, pipelineBindPoint, pipeline);
74605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
74615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7462bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetViewport(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount,
7463bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                          const VkViewport *pViewports) {
746483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
74655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
7466b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
74675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
74685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
746929f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETVIEWPORTSTATE, "vkCmdSetViewport()");
747029f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        UpdateCmdBufferLastCmd(dev_data, pCB, CMD_SETVIEWPORTSTATE);
7471bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pCB->viewportMask |= ((1u << viewportCount) - 1u) << firstViewport;
74725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7473b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7474cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetViewport(commandBuffer, firstViewport, viewportCount, pViewports);
74755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
74765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7477bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetScissor(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount,
7478bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         const VkRect2D *pScissors) {
747983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
74805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
7481b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
74825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
74835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
748429f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETSCISSORSTATE, "vkCmdSetScissor()");
748529f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        UpdateCmdBufferLastCmd(dev_data, pCB, CMD_SETSCISSORSTATE);
7486bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pCB->scissorMask |= ((1u << scissorCount) - 1u) << firstScissor;
74875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7488b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7489cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetScissor(commandBuffer, firstScissor, scissorCount, pScissors);
74905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
74915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
749289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth) {
7493a27508babf63d50aea75883a3702979193c23683Mark Young    bool skip_call = false;
74945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
7495b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
74965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
74975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
749829f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETLINEWIDTHSTATE, "vkCmdSetLineWidth()");
749929f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        UpdateCmdBufferLastCmd(dev_data, pCB, CMD_SETLINEWIDTHSTATE);
75005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_LINE_WIDTH_SET;
7501a27508babf63d50aea75883a3702979193c23683Mark Young
75024c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis        PIPELINE_STATE *pPipeTrav = pCB->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].pipeline_state;
7503a27508babf63d50aea75883a3702979193c23683Mark Young        if (pPipeTrav != NULL && !isDynamic(pPipeTrav, VK_DYNAMIC_STATE_LINE_WIDTH)) {
7504a27508babf63d50aea75883a3702979193c23683Mark Young            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0,
750555eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                 reinterpret_cast<uint64_t &>(commandBuffer), __LINE__, VALIDATION_ERROR_01476, "DS",
7506386d9a9a77f884789a7ae4c3890aecd47132f2babaldurk                                 "vkCmdSetLineWidth called but pipeline was created without VK_DYNAMIC_STATE_LINE_WIDTH "
750755eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                 "flag.  This is undefined behavior and could be ignored. %s",
750855eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                 validation_error_map[VALIDATION_ERROR_01476]);
7509a27508babf63d50aea75883a3702979193c23683Mark Young        } else {
7510a27508babf63d50aea75883a3702979193c23683Mark Young            skip_call |= verifyLineWidth(dev_data, DRAWSTATE_INVALID_SET, reinterpret_cast<uint64_t &>(commandBuffer), lineWidth);
7511a27508babf63d50aea75883a3702979193c23683Mark Young        }
75125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7513b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7514cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetLineWidth(commandBuffer, lineWidth);
75155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
75165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7517bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetDepthBias(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp,
7518bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           float depthBiasSlopeFactor) {
751983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
75205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
7521b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
75225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
75235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
752429f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETDEPTHBIASSTATE, "vkCmdSetDepthBias()");
752529f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        UpdateCmdBufferLastCmd(dev_data, pCB, CMD_SETDEPTHBIASSTATE);
75265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_DEPTH_BIAS_SET;
75275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7528b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
752983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (!skip_call)
75304a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdSetDepthBias(commandBuffer, depthBiasConstantFactor, depthBiasClamp, depthBiasSlopeFactor);
75315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
75325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
753389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdSetBlendConstants(VkCommandBuffer commandBuffer, const float blendConstants[4]) {
753483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
75355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
7536b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
75375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
75385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
753929f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETBLENDSTATE, "vkCmdSetBlendConstants()");
754029f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        UpdateCmdBufferLastCmd(dev_data, pCB, CMD_SETBLENDSTATE);
75413d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        pCB->status |= CBSTATUS_BLEND_CONSTANTS_SET;
75425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7543b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7544cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetBlendConstants(commandBuffer, blendConstants);
75455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
75465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7547bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetDepthBounds(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds) {
754883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
75495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
7550b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
75515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
75525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
755329f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETDEPTHBOUNDSSTATE, "vkCmdSetDepthBounds()");
755429f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        UpdateCmdBufferLastCmd(dev_data, pCB, CMD_SETDEPTHBOUNDSSTATE);
75555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_DEPTH_BOUNDS_SET;
75565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7557b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7558cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetDepthBounds(commandBuffer, minDepthBounds, maxDepthBounds);
75595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
75605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7561bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetStencilCompareMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask,
7562bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                    uint32_t compareMask) {
756383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
75645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
7565b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
75665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
75675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
756829f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETSTENCILREADMASKSTATE, "vkCmdSetStencilCompareMask()");
756929f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        UpdateCmdBufferLastCmd(dev_data, pCB, CMD_SETSTENCILREADMASKSTATE);
75705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_STENCIL_READ_MASK_SET;
75715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7572b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7573cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetStencilCompareMask(commandBuffer, faceMask, compareMask);
75745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
75755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7576bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetStencilWriteMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask) {
757783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
75785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
7579b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
75805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
75815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
758229f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETSTENCILWRITEMASKSTATE, "vkCmdSetStencilWriteMask()");
758329f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        UpdateCmdBufferLastCmd(dev_data, pCB, CMD_SETSTENCILWRITEMASKSTATE);
75845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_STENCIL_WRITE_MASK_SET;
75855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7586b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7587cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetStencilWriteMask(commandBuffer, faceMask, writeMask);
75885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
75895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7590bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetStencilReference(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference) {
759183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
75925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
7593b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
75945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
75955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
759629f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETSTENCILREFERENCESTATE, "vkCmdSetStencilReference()");
759729f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        UpdateCmdBufferLastCmd(dev_data, pCB, CMD_SETSTENCILREFERENCESTATE);
75985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_STENCIL_REFERENCE_SET;
75995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7600b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7601cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetStencilReference(commandBuffer, faceMask, reference);
76025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
76035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7604bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBindDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
7605bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 VkPipelineLayout layout, uint32_t firstSet, uint32_t setCount,
7606bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkDescriptorSet *pDescriptorSets, uint32_t dynamicOffsetCount,
7607bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const uint32_t *pDynamicOffsets) {
760883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
76095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
7610b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
76115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
76125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
76135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (pCB->state == CB_RECORDING) {
7614787f29d93dee194c015789cf61c079504c980572Tobin Ehlis            // Track total count of dynamic descriptor types to make sure we have an offset for each one
7615787f29d93dee194c015789cf61c079504c980572Tobin Ehlis            uint32_t totalDynamicDescriptors = 0;
7616787f29d93dee194c015789cf61c079504c980572Tobin Ehlis            string errorString = "";
7617787f29d93dee194c015789cf61c079504c980572Tobin Ehlis            uint32_t lastSetIndex = firstSet + setCount - 1;
7618dd725b03ae4d1296a722d0ec5c9fe63941cabe4bChris Forbes            if (lastSetIndex >= pCB->lastBound[pipelineBindPoint].boundDescriptorSets.size()) {
761972d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                pCB->lastBound[pipelineBindPoint].boundDescriptorSets.resize(lastSetIndex + 1);
7620dd725b03ae4d1296a722d0ec5c9fe63941cabe4bChris Forbes                pCB->lastBound[pipelineBindPoint].dynamicOffsets.resize(lastSetIndex + 1);
7621dd725b03ae4d1296a722d0ec5c9fe63941cabe4bChris Forbes            }
762271511c5a10533c910bfe62c3bcf58e2a4054e7acTobin Ehlis            auto oldFinalBoundSet = pCB->lastBound[pipelineBindPoint].boundDescriptorSets[lastSetIndex];
7623c2a5a36d03bbe52f5854a5884346e4a84115e259Tobin Ehlis            auto pipeline_layout = getPipelineLayout(dev_data, layout);
76249784e78683f658f304062235ceb2dd2c2652c357Karl Schultz            for (uint32_t set_idx = 0; set_idx < setCount; set_idx++) {
76259784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                cvdescriptorset::DescriptorSet *descriptor_set = getSetNode(dev_data, pDescriptorSets[set_idx]);
76261c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                if (descriptor_set) {
762769b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                    pCB->lastBound[pipelineBindPoint].pipeline_layout = *pipeline_layout;
76289784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                    pCB->lastBound[pipelineBindPoint].boundDescriptorSets[set_idx + firstSet] = descriptor_set;
762983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT,
76309784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                                         VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[set_idx],
76319784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                                         __LINE__, DRAWSTATE_NONE, "DS", "Descriptor Set 0x%" PRIxLEAST64 " bound on pipeline %s",
76329784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                                         (uint64_t)pDescriptorSets[set_idx], string_VkPipelineBindPoint(pipelineBindPoint));
76331c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                    if (!descriptor_set->IsUpdated() && (descriptor_set->GetTotalDescriptorCount() != 0)) {
763483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
76359784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                                             VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[set_idx],
76369784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                                             __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS",
7637d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen                                             "Descriptor Set 0x%" PRIxLEAST64
763883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                             " bound but it was never updated. You may want to either update it or not bind it.",
76399784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                                             (uint64_t)pDescriptorSets[set_idx]);
7640787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                    }
7641787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                    // Verify that set being bound is compatible with overlapping setLayout of pipelineLayout
76429784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                    if (!verify_set_layout_compatibility(dev_data, descriptor_set, pipeline_layout, set_idx + firstSet,
76439784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                                                         errorString)) {
764483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
76459784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                                             VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[set_idx],
76469784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                                             __LINE__, VALIDATION_ERROR_00974, "DS",
764783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                             "descriptorSet #%u being bound is not compatible with overlapping descriptorSetLayout "
764855eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                             "at index %u of pipelineLayout 0x%" PRIxLEAST64 " due to: %s. %s",
76499784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                                             set_idx, set_idx + firstSet, reinterpret_cast<uint64_t &>(layout), errorString.c_str(),
765055eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                             validation_error_map[VALIDATION_ERROR_00974]);
7651787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                    }
7652dd725b03ae4d1296a722d0ec5c9fe63941cabe4bChris Forbes
76531c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                    auto setDynamicDescriptorCount = descriptor_set->GetDynamicDescriptorCount();
7654dd725b03ae4d1296a722d0ec5c9fe63941cabe4bChris Forbes
76559784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                    pCB->lastBound[pipelineBindPoint].dynamicOffsets[firstSet + set_idx].clear();
7656dd725b03ae4d1296a722d0ec5c9fe63941cabe4bChris Forbes
7657dd725b03ae4d1296a722d0ec5c9fe63941cabe4bChris Forbes                    if (setDynamicDescriptorCount) {
7658787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                        // First make sure we won't overstep bounds of pDynamicOffsets array
7659dd725b03ae4d1296a722d0ec5c9fe63941cabe4bChris Forbes                        if ((totalDynamicDescriptors + setDynamicDescriptorCount) > dynamicOffsetCount) {
766083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                            skip_call |=
7661787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
76629784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                                        VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[set_idx],
76639784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                                        __LINE__, DRAWSTATE_INVALID_DYNAMIC_OFFSET_COUNT, "DS",
7664414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                                        "descriptorSet #%u (0x%" PRIxLEAST64
7665787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                                        ") requires %u dynamicOffsets, but only %u dynamicOffsets are left in pDynamicOffsets "
7666787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                                        "array. There must be one dynamic offset for each dynamic descriptor being bound.",
76679784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                                        set_idx, (uint64_t)pDescriptorSets[set_idx], descriptor_set->GetDynamicDescriptorCount(),
7668787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                                        (dynamicOffsetCount - totalDynamicDescriptors));
7669cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        } else {  // Validate and store dynamic offsets with the set
7670787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                            // Validate Dynamic Offset Minimums
7671787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                            uint32_t cur_dyn_offset = totalDynamicDescriptors;
76721c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                            for (uint32_t d = 0; d < descriptor_set->GetTotalDescriptorCount(); d++) {
76731c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                                if (descriptor_set->GetTypeFromGlobalIndex(d) == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) {
7674787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                                    if (vk_safe_modulo(
7675787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                                            pDynamicOffsets[cur_dyn_offset],
7676b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis                                            dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment) != 0) {
767783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                        skip_call |= log_msg(
7678787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                                            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
767955eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                            VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, VALIDATION_ERROR_00978,
7680cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "DS",
7681cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "vkCmdBindDescriptorSets(): pDynamicOffsets[%d] is %d but must be a multiple of "
7682cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "device limit minUniformBufferOffsetAlignment 0x%" PRIxLEAST64 ". %s",
7683787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                                            cur_dyn_offset, pDynamicOffsets[cur_dyn_offset],
768455eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                            dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment,
768555eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                            validation_error_map[VALIDATION_ERROR_00978]);
7686787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                                    }
7687787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                                    cur_dyn_offset++;
76881c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                                } else if (descriptor_set->GetTypeFromGlobalIndex(d) == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
7689787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                                    if (vk_safe_modulo(
7690787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                                            pDynamicOffsets[cur_dyn_offset],
7691b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis                                            dev_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment) != 0) {
769283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                        skip_call |= log_msg(
7693787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                                            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
769455eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                            VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, VALIDATION_ERROR_00978,
7695cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "DS",
7696cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "vkCmdBindDescriptorSets(): pDynamicOffsets[%d] is %d but must be a multiple of "
7697cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "device limit minStorageBufferOffsetAlignment 0x%" PRIxLEAST64 ". %s",
7698787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                                            cur_dyn_offset, pDynamicOffsets[cur_dyn_offset],
769955eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                            dev_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment,
770055eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                            validation_error_map[VALIDATION_ERROR_00978]);
77015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                    }
7702787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                                    cur_dyn_offset++;
77035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                }
77045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                            }
7705dd725b03ae4d1296a722d0ec5c9fe63941cabe4bChris Forbes
77069784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                            pCB->lastBound[pipelineBindPoint].dynamicOffsets[firstSet + set_idx] =
7707dd725b03ae4d1296a722d0ec5c9fe63941cabe4bChris Forbes                                std::vector<uint32_t>(pDynamicOffsets + totalDynamicDescriptors,
7708dd725b03ae4d1296a722d0ec5c9fe63941cabe4bChris Forbes                                                      pDynamicOffsets + totalDynamicDescriptors + setDynamicDescriptorCount);
7709787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                            // Keep running total of dynamic descriptor count to verify at the end
7710dd725b03ae4d1296a722d0ec5c9fe63941cabe4bChris Forbes                            totalDynamicDescriptors += setDynamicDescriptorCount;
77115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        }
77125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
7713787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                } else {
77149784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
77159784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                                         VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[set_idx],
77169784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                                         __LINE__, DRAWSTATE_INVALID_SET, "DS",
77179784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                                         "Attempt to bind descriptor set 0x%" PRIxLEAST64 " that doesn't exist!",
77189784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                                         (uint64_t)pDescriptorSets[set_idx]);
77195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
772029f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis                skip_call |= ValidateCmd(dev_data, pCB, CMD_BINDDESCRIPTORSETS, "vkCmdBindDescriptorSets()");
772129f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis                UpdateCmdBufferLastCmd(dev_data, pCB, CMD_BINDDESCRIPTORSETS);
772272d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                // For any previously bound sets, need to set them to "invalid" if they were disturbed by this update
7723cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (firstSet > 0) {  // Check set #s below the first bound set
772472d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                    for (uint32_t i = 0; i < firstSet; ++i) {
772572d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                        if (pCB->lastBound[pipelineBindPoint].boundDescriptorSets[i] &&
772671511c5a10533c910bfe62c3bcf58e2a4054e7acTobin Ehlis                            !verify_set_layout_compatibility(dev_data, pCB->lastBound[pipelineBindPoint].boundDescriptorSets[i],
772769b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                                                             pipeline_layout, i, errorString)) {
772883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                            skip_call |= log_msg(
772972d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                                dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
773072d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                                VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
773172d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                                (uint64_t)pCB->lastBound[pipelineBindPoint].boundDescriptorSets[i], __LINE__, DRAWSTATE_NONE, "DS",
7732d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen                                "DescriptorSet 0x%" PRIxLEAST64
7733414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                                " previously bound as set #%u was disturbed by newly bound pipelineLayout (0x%" PRIxLEAST64 ")",
773472d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                                (uint64_t)pCB->lastBound[pipelineBindPoint].boundDescriptorSets[i], i, (uint64_t)layout);
773572d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                            pCB->lastBound[pipelineBindPoint].boundDescriptorSets[i] = VK_NULL_HANDLE;
773672d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                        }
773772d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                    }
773872d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                }
773972d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                // Check if newly last bound set invalidates any remaining bound sets
774072d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                if ((pCB->lastBound[pipelineBindPoint].boundDescriptorSets.size() - 1) > (lastSetIndex)) {
774172d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                    if (oldFinalBoundSet &&
774269b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                        !verify_set_layout_compatibility(dev_data, oldFinalBoundSet, pipeline_layout, lastSetIndex, errorString)) {
774371511c5a10533c910bfe62c3bcf58e2a4054e7acTobin Ehlis                        auto old_set = oldFinalBoundSet->GetSet();
774483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                        skip_call |=
774572d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                            log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
774671511c5a10533c910bfe62c3bcf58e2a4054e7acTobin Ehlis                                    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, reinterpret_cast<uint64_t &>(old_set), __LINE__,
7747d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen                                    DRAWSTATE_NONE, "DS", "DescriptorSet 0x%" PRIxLEAST64
7748414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                                                          " previously bound as set #%u is incompatible with set 0x%" PRIxLEAST64
774972d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                                                          " newly bound as set #%u so set #%u and any subsequent sets were "
7750414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                                                          "disturbed by newly bound pipelineLayout (0x%" PRIxLEAST64 ")",
775171511c5a10533c910bfe62c3bcf58e2a4054e7acTobin Ehlis                                    reinterpret_cast<uint64_t &>(old_set), lastSetIndex,
775272d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                                    (uint64_t)pCB->lastBound[pipelineBindPoint].boundDescriptorSets[lastSetIndex], lastSetIndex,
775372d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                                    lastSetIndex + 1, (uint64_t)layout);
775472d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                        pCB->lastBound[pipelineBindPoint].boundDescriptorSets.resize(lastSetIndex + 1);
77555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
77565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
77575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
7758787f29d93dee194c015789cf61c079504c980572Tobin Ehlis            //  dynamicOffsetCount must equal the total number of dynamic descriptors in the sets being bound
7759787f29d93dee194c015789cf61c079504c980572Tobin Ehlis            if (totalDynamicDescriptors != dynamicOffsetCount) {
776083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                skip_call |=
776183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
776255eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                            (uint64_t)commandBuffer, __LINE__, VALIDATION_ERROR_00975, "DS",
776383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                            "Attempting to bind %u descriptorSets with %u dynamic descriptors, but dynamicOffsetCount "
776455eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                            "is %u. It should exactly match the number of dynamic descriptors. %s",
776555eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                            setCount, totalDynamicDescriptors, dynamicOffsetCount, validation_error_map[VALIDATION_ERROR_00975]);
7766787f29d93dee194c015789cf61c079504c980572Tobin Ehlis            }
77675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
776883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdBindDescriptorSets()");
77695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
77705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7771b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
777283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (!skip_call)
77734a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdBindDescriptorSets(commandBuffer, pipelineBindPoint, layout, firstSet, setCount,
77744a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                       pDescriptorSets, dynamicOffsetCount, pDynamicOffsets);
77755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
77765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7777bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBindIndexBuffer(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
7778bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              VkIndexType indexType) {
777983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
77805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
7781593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis    // TODO : Somewhere need to verify that IBs have correct usage state flagged
7782b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7783b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski
77845cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    auto buffer_state = getBufferState(dev_data, buffer);
77859f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis    auto cb_node = getCBNode(dev_data, commandBuffer);
77865cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (cb_node && buffer_state) {
778735ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis        skip_call |= ValidateMemoryIsBoundToBuffer(dev_data, buffer_state, "vkCmdBindIndexBuffer()", VALIDATION_ERROR_02543);
7788ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        std::function<bool()> function = [=]() {
77895cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            return ValidateBufferMemoryIsValid(dev_data, buffer_state, "vkCmdBindIndexBuffer()");
7790ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        };
77919f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
779229f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, cb_node, CMD_BINDINDEXBUFFER, "vkCmdBindIndexBuffer()");
779329f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        UpdateCmdBufferLastCmd(dev_data, cb_node, CMD_BINDINDEXBUFFER);
77945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        VkDeviceSize offset_align = 0;
77955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        switch (indexType) {
7796cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_INDEX_TYPE_UINT16:
7797cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                offset_align = 2;
7798cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
7799cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_INDEX_TYPE_UINT32:
7800cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                offset_align = 4;
7801cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
7802cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
7803cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // ParamChecker should catch bad enum, we'll also throw alignment error below if offset_align stays 0
7804cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
78055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
78065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!offset_align || (offset % offset_align)) {
780783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
780883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 DRAWSTATE_VTX_INDEX_ALIGNMENT_ERROR, "DS",
780983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 "vkCmdBindIndexBuffer() offset (0x%" PRIxLEAST64 ") does not fall on alignment (%s) boundary.",
781083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 offset, string_VkIndexType(indexType));
78115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
78129f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->status |= CBSTATUS_INDEX_BUFFER_BOUND;
7813ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
7814ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
78155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7816b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7817cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdBindIndexBuffer(commandBuffer, buffer, offset, indexType);
78185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
78195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
78205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisvoid updateResourceTracking(GLOBAL_CB_NODE *pCB, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer *pBuffers) {
78215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t end = firstBinding + bindingCount;
78225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB->currentDrawData.buffers.size() < end) {
78235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->currentDrawData.buffers.resize(end);
78245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
78255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < bindingCount; ++i) {
78265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->currentDrawData.buffers[i + firstBinding] = pBuffers[i];
78275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
78285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
78295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7830e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic inline void updateResourceTrackingOnDraw(GLOBAL_CB_NODE *pCB) { pCB->drawData.push_back(pCB->currentDrawData); }
78315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7832bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBindVertexBuffers(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount,
7833bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkBuffer *pBuffers, const VkDeviceSize *pOffsets) {
783483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
78355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
7836593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis    // TODO : Somewhere need to verify that VBs have correct usage state flagged
7837b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7838b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski
78399f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis    auto cb_node = getCBNode(dev_data, commandBuffer);
78409f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis    if (cb_node) {
7841593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        for (uint32_t i = 0; i < bindingCount; ++i) {
78425cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            auto buffer_state = getBufferState(dev_data, pBuffers[i]);
78435cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            assert(buffer_state);
784435ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis            skip_call |= ValidateMemoryIsBoundToBuffer(dev_data, buffer_state, "vkCmdBindVertexBuffers()", VALIDATION_ERROR_02546);
7845ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis            std::function<bool()> function = [=]() {
78465cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis                return ValidateBufferMemoryIsValid(dev_data, buffer_state, "vkCmdBindVertexBuffers()");
7847ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis            };
78489f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis            cb_node->validate_functions.push_back(function);
78495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
785029f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, cb_node, CMD_BINDVERTEXBUFFER, "vkCmdBindVertexBuffer()");
785129f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        UpdateCmdBufferLastCmd(dev_data, cb_node, CMD_BINDVERTEXBUFFER);
78529f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        updateResourceTracking(cb_node, firstBinding, bindingCount, pBuffers);
78535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
785483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis        skip_call |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdBindVertexBuffer()");
78555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7856b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7857cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdBindVertexBuffers(commandBuffer, firstBinding, bindingCount, pBuffers, pOffsets);
78585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
78595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
786025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// Expects global_lock to be held by caller
78615569d6457ac22e7d245f3cdee045e71ffbc8b06eTobin Ehlisstatic void MarkStoreImagesAndBuffersAsWritten(layer_data *dev_data, GLOBAL_CB_NODE *pCB) {
78627a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis    for (auto imageView : pCB->updateImages) {
786379fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis        auto view_state = getImageViewState(dev_data, imageView);
7864cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!view_state) continue;
7865249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis
78661facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        auto image_state = getImageState(dev_data, view_state->create_info.image);
78671facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        assert(image_state);
7868e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
78691facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            SetImageMemoryValid(dev_data, image_state, true);
7870e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
78717a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        };
78727a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        pCB->validate_functions.push_back(function);
78737a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis    }
78747a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis    for (auto buffer : pCB->updateBuffers) {
78755cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        auto buffer_state = getBufferState(dev_data, buffer);
78765cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        assert(buffer_state);
7877e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
78785cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            SetBufferMemoryValid(dev_data, buffer_state, true);
7879e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
78807a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        };
78817a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        pCB->validate_functions.push_back(function);
78825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
78835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
78845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7885ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis// Generic function to handle validation for all CmdDraw* type functions
7886ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool ValidateCmdDrawType(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed, VkPipelineBindPoint bind_point,
7887ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                CMD_TYPE cmd_type, GLOBAL_CB_NODE **cb_state, const char *caller,
78884f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                UNIQUE_VALIDATION_ERROR_CODE msg_code, UNIQUE_VALIDATION_ERROR_CODE const dynamic_state_msg_code) {
788958b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    bool skip = false;
789058b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    *cb_state = getCBNode(dev_data, cmd_buffer);
789158b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    if (*cb_state) {
7892ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis        skip |= ValidateCmd(dev_data, *cb_state, cmd_type, caller);
78934f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes        skip |= ValidateDrawState(dev_data, *cb_state, indexed, bind_point, caller, dynamic_state_msg_code);
789425d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis        skip |= (VK_PIPELINE_BIND_POINT_GRAPHICS == bind_point) ? outsideRenderPass(dev_data, *cb_state, caller, msg_code)
789525d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis                                                                : insideRenderPass(dev_data, *cb_state, caller, msg_code);
789658b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    }
789758b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    return skip;
789858b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis}
789958b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis
790025d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis// Generic function to handle state update for all CmdDraw* and CmdDispatch* type functions
7901ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void UpdateStateCmdDrawDispatchType(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
7902ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                           CMD_TYPE cmd_type) {
7903ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateDrawState(dev_data, cb_state, bind_point);
79042f921d33544c162dcb726fc3c7b915e89c02ff24Tobin Ehlis    MarkStoreImagesAndBuffersAsWritten(dev_data, cb_state);
790525d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis    UpdateCmdBufferLastCmd(dev_data, cb_state, cmd_type);
790625d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis}
790725d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis
7908ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis// Generic function to handle state update for all CmdDraw* type functions
7909ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void UpdateStateCmdDrawType(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
7910ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                   CMD_TYPE cmd_type, DRAW_TYPE draw_type) {
7911ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawDispatchType(dev_data, cb_state, bind_point, cmd_type);
7912c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis    updateResourceTrackingOnDraw(cb_state);
7913ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    cb_state->drawCount[draw_type]++;
7914ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis}
7915ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis
7916ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDraw(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed, VkPipelineBindPoint bind_point,
7917ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                   GLOBAL_CB_NODE **cb_state, const char *caller) {
79184f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes    return ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAW, cb_state, caller, VALIDATION_ERROR_01365,
79194f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                               VALIDATION_ERROR_02203);
7920ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis}
7921ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis
7922ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDraw(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point) {
7923ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawType(dev_data, cb_state, bind_point, CMD_DRAW, DRAW);
7924c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis}
7925c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis
792689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount,
792789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                   uint32_t firstVertex, uint32_t firstInstance) {
79285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
792958b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
7930b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7931ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    bool skip = PreCallValidateCmdDraw(dev_data, commandBuffer, false, VK_PIPELINE_BIND_POINT_GRAPHICS, &cb_state, "vkCmdDraw()");
7932b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
793358b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    if (!skip) {
79344a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDraw(commandBuffer, vertexCount, instanceCount, firstVertex, firstInstance);
7935c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis        lock.lock();
7936ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDraw(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS);
7937c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis        lock.unlock();
7938c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis    }
79395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
79405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7941ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDrawIndexed(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed,
7942ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                          VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state, const char *caller) {
79434f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes    return ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAWINDEXED, cb_state, caller, VALIDATION_ERROR_01372,
79444f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                               VALIDATION_ERROR_02216);
7945ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis}
7946ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis
7947ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDrawIndexed(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point) {
7948ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawType(dev_data, cb_state, bind_point, CMD_DRAWINDEXED, DRAW_INDEXED);
7949ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis}
7950ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis
7951bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount,
7952bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                          uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance) {
79535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
7954ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
7955b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7956ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    bool skip = PreCallValidateCmdDrawIndexed(dev_data, commandBuffer, true, VK_PIPELINE_BIND_POINT_GRAPHICS, &cb_state,
7957ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                              "vkCmdDrawIndexed()");
7958b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7959ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    if (!skip) {
79604a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDrawIndexed(commandBuffer, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
7961ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis        lock.lock();
7962ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDrawIndexed(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS);
7963ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis        lock.unlock();
7964ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    }
79655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
79665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7967ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDrawIndirect(layer_data *dev_data, VkCommandBuffer cmd_buffer, VkBuffer buffer, bool indexed,
7968ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                           VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state, BUFFER_STATE **buffer_state,
7969ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                           const char *caller) {
79704f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes    bool skip = ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAWINDIRECT, cb_state, caller,
79714f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                    VALIDATION_ERROR_01381, VALIDATION_ERROR_02234);
7972d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    *buffer_state = getBufferState(dev_data, buffer);
797335ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis    skip |= ValidateMemoryIsBoundToBuffer(dev_data, *buffer_state, caller, VALIDATION_ERROR_02544);
7974d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    return skip;
7975d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis}
7976d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis
7977ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDrawIndirect(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
7978ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                          BUFFER_STATE *buffer_state) {
7979ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawType(dev_data, cb_state, bind_point, CMD_DRAWINDIRECT, DRAW_INDIRECT);
7980d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    AddCommandBufferBindingBuffer(dev_data, cb_state, buffer_state);
7981d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis}
7982d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis
7983bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count,
7984bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           uint32_t stride) {
79855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
7986d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
7987d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    BUFFER_STATE *buffer_state = nullptr;
7988b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7989872a2f0ca3ffdeddfa7483e777191fa64b853892Tony Barbour    bool skip = PreCallValidateCmdDrawIndirect(dev_data, commandBuffer, buffer, false, VK_PIPELINE_BIND_POINT_GRAPHICS, &cb_state,
7990ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                               &buffer_state, "vkCmdDrawIndirect()");
7991b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7992d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    if (!skip) {
79934a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDrawIndirect(commandBuffer, buffer, offset, count, stride);
7994d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis        lock.lock();
7995ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDrawIndirect(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, buffer_state);
7996d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis        lock.unlock();
7997d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    }
79985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
79995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8000ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDrawIndexedIndirect(layer_data *dev_data, VkCommandBuffer cmd_buffer, VkBuffer buffer, bool indexed,
8001ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                  VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state,
8002ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                  BUFFER_STATE **buffer_state, const char *caller) {
8003ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    bool skip = ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAWINDEXEDINDIRECT, cb_state, caller,
80044f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                    VALIDATION_ERROR_01393, VALIDATION_ERROR_02272);
80050c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    *buffer_state = getBufferState(dev_data, buffer);
800635ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis    skip |= ValidateMemoryIsBoundToBuffer(dev_data, *buffer_state, caller, VALIDATION_ERROR_02545);
80070c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    return skip;
80080c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis}
80090c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis
8010ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDrawIndexedIndirect(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
8011ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                 BUFFER_STATE *buffer_state) {
8012ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawType(dev_data, cb_state, bind_point, CMD_DRAWINDEXEDINDIRECT, DRAW_INDEXED_INDIRECT);
80130c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    AddCommandBufferBindingBuffer(dev_data, cb_state, buffer_state);
80140c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis}
80150c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis
8016bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
8017bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                  uint32_t count, uint32_t stride) {
80185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
80190c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
80200c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    BUFFER_STATE *buffer_state = nullptr;
8021b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
80220c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    bool skip = PreCallValidateCmdDrawIndexedIndirect(dev_data, commandBuffer, buffer, true, VK_PIPELINE_BIND_POINT_GRAPHICS,
8023ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                      &cb_state, &buffer_state, "vkCmdDrawIndexedIndirect()");
8024b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
80250c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    if (!skip) {
80264a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDrawIndexedIndirect(commandBuffer, buffer, offset, count, stride);
80270c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis        lock.lock();
8028ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDrawIndexedIndirect(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, buffer_state);
80290c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis        lock.unlock();
80300c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    }
80315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
80325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8033ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDispatch(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed,
8034ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                       VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state, const char *caller) {
80354f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes    return ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DISPATCH, cb_state, caller, VALIDATION_ERROR_01562,
80364f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                               VALIDATION_ERROR_UNDEFINED);
803725d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis}
803825d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis
8039ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDispatch(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point) {
8040ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawDispatchType(dev_data, cb_state, bind_point, CMD_DISPATCH);
804125d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis}
804225d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis
804389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z) {
80445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
804525d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
8046b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
8047ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    bool skip =
8048ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PreCallValidateCmdDispatch(dev_data, commandBuffer, false, VK_PIPELINE_BIND_POINT_COMPUTE, &cb_state, "vkCmdDispatch()");
8049b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
805025d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis    if (!skip) {
80514a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDispatch(commandBuffer, x, y, z);
805225d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis        lock.lock();
8053ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDispatch(dev_data, cb_state, VK_PIPELINE_BIND_POINT_COMPUTE);
805425d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis        lock.unlock();
805525d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis    }
80565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
80575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8058ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDispatchIndirect(layer_data *dev_data, VkCommandBuffer cmd_buffer, VkBuffer buffer, bool indexed,
8059ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                               VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state,
8060ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                               BUFFER_STATE **buffer_state, const char *caller) {
8061ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    bool skip = ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DISPATCHINDIRECT, cb_state, caller,
80624f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                    VALIDATION_ERROR_01569, VALIDATION_ERROR_UNDEFINED);
806379c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    *buffer_state = getBufferState(dev_data, buffer);
806435ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis    skip |= ValidateMemoryIsBoundToBuffer(dev_data, *buffer_state, caller, VALIDATION_ERROR_02547);
806579c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    return skip;
806679c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis}
806779c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis
8068ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDispatchIndirect(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
8069ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                              BUFFER_STATE *buffer_state) {
8070ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawDispatchType(dev_data, cb_state, bind_point, CMD_DISPATCHINDIRECT);
807179c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    AddCommandBufferBindingBuffer(dev_data, cb_state, buffer_state);
807279c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis}
807379c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis
8074bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset) {
80755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
807679c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
807779c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    BUFFER_STATE *buffer_state = nullptr;
8078b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
80797433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis    bool skip = PreCallValidateCmdDispatchIndirect(dev_data, commandBuffer, buffer, false, VK_PIPELINE_BIND_POINT_COMPUTE,
8080ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                   &cb_state, &buffer_state, "vkCmdDispatchIndirect()");
8081b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
808279c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    if (!skip) {
80834a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDispatchIndirect(commandBuffer, buffer, offset);
808479c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis        lock.lock();
8085ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDispatchIndirect(dev_data, cb_state, VK_PIPELINE_BIND_POINT_COMPUTE, buffer_state);
808679c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis        lock.unlock();
808779c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    }
80885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
80895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
809089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
809189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                         uint32_t regionCount, const VkBufferCopy *pRegions) {
809283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
80935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
8094b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
8095ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
80969f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis    auto cb_node = getCBNode(dev_data, commandBuffer);
80975cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    auto src_buff_state = getBufferState(dev_data, srcBuffer);
80985cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    auto dst_buff_state = getBufferState(dev_data, dstBuffer);
80995cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (cb_node && src_buff_state && dst_buff_state) {
810035ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis        skip_call |= ValidateMemoryIsBoundToBuffer(dev_data, src_buff_state, "vkCmdCopyBuffer()", VALIDATION_ERROR_02531);
810135ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis        skip_call |= ValidateMemoryIsBoundToBuffer(dev_data, dst_buff_state, "vkCmdCopyBuffer()", VALIDATION_ERROR_02532);
8102ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Update bindings between buffers and cmd buffer
81035cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        AddCommandBufferBindingBuffer(dev_data, cb_node, src_buff_state);
81045cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        AddCommandBufferBindingBuffer(dev_data, cb_node, dst_buff_state);
8105ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Validate that SRC & DST buffers have correct usage flags set
81065cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        skip_call |= ValidateBufferUsageFlags(dev_data, src_buff_state, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, true,
81071b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes                                              VALIDATION_ERROR_01164, "vkCmdCopyBuffer()", "VK_BUFFER_USAGE_TRANSFER_SRC_BIT");
81085cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        skip_call |= ValidateBufferUsageFlags(dev_data, dst_buff_state, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true,
81091b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes                                              VALIDATION_ERROR_01165, "vkCmdCopyBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
8110ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
8111ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        std::function<bool()> function = [=]() {
81125cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            return ValidateBufferMemoryIsValid(dev_data, src_buff_state, "vkCmdCopyBuffer()");
8113ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        };
81149f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
8115593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        function = [=]() {
81165cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            SetBufferMemoryValid(dev_data, dst_buff_state, true);
8117e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
81185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        };
81199f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
8120593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
812129f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, cb_node, CMD_COPYBUFFER, "vkCmdCopyBuffer()");
812229f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        UpdateCmdBufferLastCmd(dev_data, cb_node, CMD_COPYBUFFER);
8123ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen        skip_call |= insideRenderPass(dev_data, cb_node, "vkCmdCopyBuffer()", VALIDATION_ERROR_01172);
8124ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
8125ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Param_checker will flag errors on invalid objects, just assert here as debugging aid
8126ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
81275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8128b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8129cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, regionCount, pRegions);
81305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
81315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
813227e2917587adf1738c71851a128806f7de578cbeTobin Ehlisstatic bool VerifySourceImageLayout(layer_data *dev_data, GLOBAL_CB_NODE *cb_node, VkImage srcImage,
813355eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                    VkImageSubresourceLayers subLayers, VkImageLayout srcImageLayout,
813455eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                    UNIQUE_VALIDATION_ERROR_CODE msgCode) {
8135e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
81365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
81375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < subLayers.layerCount; ++i) {
81385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t layer = i + subLayers.baseArrayLayer;
81395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        VkImageSubresource sub = {subLayers.aspectMask, subLayers.mipLevel, layer};
81405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        IMAGE_CMD_BUF_LAYOUT_NODE node;
814127e2917587adf1738c71851a128806f7de578cbeTobin Ehlis        if (!FindLayout(cb_node, srcImage, sub, node)) {
814227e2917587adf1738c71851a128806f7de578cbeTobin Ehlis            SetLayout(cb_node, srcImage, sub, IMAGE_CMD_BUF_LAYOUT_NODE(srcImageLayout, srcImageLayout));
81435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            continue;
81445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
81455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (node.layout != srcImageLayout) {
81465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // TODO: Improve log message in the next pass
8147cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
8148cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
8149cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "Cannot copy from an image whose source layout is %s "
8150cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "and doesn't match the current layout %s.",
8151cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 string_VkImageLayout(srcImageLayout), string_VkImageLayout(node.layout));
81525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
81535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
81545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (srcImageLayout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) {
81555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (srcImageLayout == VK_IMAGE_LAYOUT_GENERAL) {
815607b081bc51bf0151b7d2074967b948c02961c166Tobin Ehlis            // TODO : Can we deal with image node from the top of call tree and avoid map look-up here?
81571facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            auto image_state = getImageState(dev_data, srcImage);
81581facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            if (image_state->createInfo.tiling != VK_IMAGE_TILING_LINEAR) {
815907b081bc51bf0151b7d2074967b948c02961c166Tobin Ehlis                // LAYOUT_GENERAL is allowed, but may not be performance optimal, flag as perf warning.
816007b081bc51bf0151b7d2074967b948c02961c166Tobin Ehlis                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
816107b081bc51bf0151b7d2074967b948c02961c166Tobin Ehlis                                     (VkDebugReportObjectTypeEXT)0, 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
816207b081bc51bf0151b7d2074967b948c02961c166Tobin Ehlis                                     "Layout for input image should be TRANSFER_SRC_OPTIMAL instead of GENERAL.");
816307b081bc51bf0151b7d2074967b948c02961c166Tobin Ehlis            }
81645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
81655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
816655eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                 msgCode, "DS", "Layout for input image is %s but can only be TRANSFER_SRC_OPTIMAL or GENERAL. %s",
816755eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                 string_VkImageLayout(srcImageLayout), validation_error_map[msgCode]);
81685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
81695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
81705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
81715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
81725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
817327e2917587adf1738c71851a128806f7de578cbeTobin Ehlisstatic bool VerifyDestImageLayout(layer_data *dev_data, GLOBAL_CB_NODE *cb_node, VkImage destImage,
817455eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                  VkImageSubresourceLayers subLayers, VkImageLayout destImageLayout,
817555eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                  UNIQUE_VALIDATION_ERROR_CODE msgCode) {
8176e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
81775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
81785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < subLayers.layerCount; ++i) {
81795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t layer = i + subLayers.baseArrayLayer;
81805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        VkImageSubresource sub = {subLayers.aspectMask, subLayers.mipLevel, layer};
81815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        IMAGE_CMD_BUF_LAYOUT_NODE node;
818227e2917587adf1738c71851a128806f7de578cbeTobin Ehlis        if (!FindLayout(cb_node, destImage, sub, node)) {
818327e2917587adf1738c71851a128806f7de578cbeTobin Ehlis            SetLayout(cb_node, destImage, sub, IMAGE_CMD_BUF_LAYOUT_NODE(destImageLayout, destImageLayout));
81845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            continue;
81855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
81865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (node.layout != destImageLayout) {
8187cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
8188cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
8189cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "Cannot copy from an image whose dest layout is %s and "
8190cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "doesn't match the current layout %s.",
8191cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 string_VkImageLayout(destImageLayout), string_VkImageLayout(node.layout));
81925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
81935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
81945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (destImageLayout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
81955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (destImageLayout == VK_IMAGE_LAYOUT_GENERAL) {
81961facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            auto image_state = getImageState(dev_data, destImage);
81971facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            if (image_state->createInfo.tiling != VK_IMAGE_TILING_LINEAR) {
819807b081bc51bf0151b7d2074967b948c02961c166Tobin Ehlis                // LAYOUT_GENERAL is allowed, but may not be performance optimal, flag as perf warning.
819907b081bc51bf0151b7d2074967b948c02961c166Tobin Ehlis                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
820007b081bc51bf0151b7d2074967b948c02961c166Tobin Ehlis                                     (VkDebugReportObjectTypeEXT)0, 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
820107b081bc51bf0151b7d2074967b948c02961c166Tobin Ehlis                                     "Layout for output image should be TRANSFER_DST_OPTIMAL instead of GENERAL.");
820207b081bc51bf0151b7d2074967b948c02961c166Tobin Ehlis            }
82035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
82045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
820555eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                 msgCode, "DS", "Layout for output image is %s but can only be TRANSFER_DST_OPTIMAL or GENERAL. %s",
820655eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                 string_VkImageLayout(destImageLayout), validation_error_map[msgCode]);
82075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
82085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
82095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
82105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
82115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
82127f8aa8f5abceedbb599ef69af1dfbb38c0df2660Slawomir Cyganstatic bool VerifyClearImageLayout(layer_data *dev_data, GLOBAL_CB_NODE *cb_node, VkImage image, VkImageSubresourceRange range,
8213777507259dcf34d32d0cb1f6820583455a4a8377Cort                                   VkImageLayout dest_image_layout, const char *func_name) {
8214777507259dcf34d32d0cb1f6820583455a4a8377Cort    bool skip = false;
82157f8aa8f5abceedbb599ef69af1dfbb38c0df2660Slawomir Cygan
82167f8aa8f5abceedbb599ef69af1dfbb38c0df2660Slawomir Cygan    VkImageSubresourceRange resolvedRange = range;
82177f8aa8f5abceedbb599ef69af1dfbb38c0df2660Slawomir Cygan    ResolveRemainingLevelsLayers(dev_data, &resolvedRange, image);
82187f8aa8f5abceedbb599ef69af1dfbb38c0df2660Slawomir Cygan
8219777507259dcf34d32d0cb1f6820583455a4a8377Cort    if (dest_image_layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
8220777507259dcf34d32d0cb1f6820583455a4a8377Cort        if (dest_image_layout == VK_IMAGE_LAYOUT_GENERAL) {
82211c2dd65baf29dba7c39172cf25f296a25baa4f3aCort            auto image_state = getImageState(dev_data, image);
82221c2dd65baf29dba7c39172cf25f296a25baa4f3aCort            if (image_state->createInfo.tiling != VK_IMAGE_TILING_LINEAR) {
82231c2dd65baf29dba7c39172cf25f296a25baa4f3aCort                // LAYOUT_GENERAL is allowed, but may not be performance optimal, flag as perf warning.
8224777507259dcf34d32d0cb1f6820583455a4a8377Cort                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0,
8225777507259dcf34d32d0cb1f6820583455a4a8377Cort                                0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
8226777507259dcf34d32d0cb1f6820583455a4a8377Cort                                "%s: Layout for cleared image should be TRANSFER_DST_OPTIMAL instead of GENERAL.", func_name);
82271c2dd65baf29dba7c39172cf25f296a25baa4f3aCort            }
82281c2dd65baf29dba7c39172cf25f296a25baa4f3aCort        } else {
8229777507259dcf34d32d0cb1f6820583455a4a8377Cort            UNIQUE_VALIDATION_ERROR_CODE error_code = VALIDATION_ERROR_01086;
8230777507259dcf34d32d0cb1f6820583455a4a8377Cort            if (strcmp(func_name, "vkCmdClearDepthStencilImage()") == 0) {
82311c2dd65baf29dba7c39172cf25f296a25baa4f3aCort                error_code = VALIDATION_ERROR_01101;
82321c2dd65baf29dba7c39172cf25f296a25baa4f3aCort            } else {
8233777507259dcf34d32d0cb1f6820583455a4a8377Cort                assert(strcmp(func_name, "vkCmdClearColorImage()") == 0);
82341c2dd65baf29dba7c39172cf25f296a25baa4f3aCort            }
8235777507259dcf34d32d0cb1f6820583455a4a8377Cort            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8236cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            error_code, "DS",
8237cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s: Layout for cleared image is %s but can only be "
8238cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "TRANSFER_DST_OPTIMAL or GENERAL. %s",
8239777507259dcf34d32d0cb1f6820583455a4a8377Cort                            func_name, string_VkImageLayout(dest_image_layout), validation_error_map[error_code]);
82401c2dd65baf29dba7c39172cf25f296a25baa4f3aCort        }
82411c2dd65baf29dba7c39172cf25f296a25baa4f3aCort    }
82421c2dd65baf29dba7c39172cf25f296a25baa4f3aCort
8243f42137395b61565d9d8e491f2999af1888168207Karl Schultz    for (uint32_t levelIdx = 0; levelIdx < resolvedRange.levelCount; ++levelIdx) {
8244f42137395b61565d9d8e491f2999af1888168207Karl Schultz        uint32_t level = levelIdx + resolvedRange.baseMipLevel;
8245f42137395b61565d9d8e491f2999af1888168207Karl Schultz        for (uint32_t layerIdx = 0; layerIdx < resolvedRange.layerCount; ++layerIdx) {
8246f42137395b61565d9d8e491f2999af1888168207Karl Schultz            uint32_t layer = layerIdx + resolvedRange.baseArrayLayer;
8247f42137395b61565d9d8e491f2999af1888168207Karl Schultz            VkImageSubresource sub = {resolvedRange.aspectMask, level, layer};
82487f8aa8f5abceedbb599ef69af1dfbb38c0df2660Slawomir Cygan            IMAGE_CMD_BUF_LAYOUT_NODE node;
82497f8aa8f5abceedbb599ef69af1dfbb38c0df2660Slawomir Cygan            if (!FindLayout(cb_node, image, sub, node)) {
8250777507259dcf34d32d0cb1f6820583455a4a8377Cort                SetLayout(cb_node, image, sub, IMAGE_CMD_BUF_LAYOUT_NODE(dest_image_layout, dest_image_layout));
82517f8aa8f5abceedbb599ef69af1dfbb38c0df2660Slawomir Cygan                continue;
82527f8aa8f5abceedbb599ef69af1dfbb38c0df2660Slawomir Cygan            }
8253777507259dcf34d32d0cb1f6820583455a4a8377Cort            if (node.layout != dest_image_layout) {
8254777507259dcf34d32d0cb1f6820583455a4a8377Cort                UNIQUE_VALIDATION_ERROR_CODE error_code = VALIDATION_ERROR_01085;
8255777507259dcf34d32d0cb1f6820583455a4a8377Cort                if (strcmp(func_name, "vkCmdClearDepthStencilImage()") == 0) {
82561c2dd65baf29dba7c39172cf25f296a25baa4f3aCort                    error_code = VALIDATION_ERROR_01100;
82571c2dd65baf29dba7c39172cf25f296a25baa4f3aCort                } else {
8258777507259dcf34d32d0cb1f6820583455a4a8377Cort                    assert(strcmp(func_name, "vkCmdClearColorImage()") == 0);
82591c2dd65baf29dba7c39172cf25f296a25baa4f3aCort                }
8260cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
8261cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, error_code, "DS",
8262cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                "%s: Cannot clear an image whose layout is %s and "
8263cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                "doesn't match the current layout %s. %s",
8264cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                func_name, string_VkImageLayout(dest_image_layout), string_VkImageLayout(node.layout),
8265cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                validation_error_map[error_code]);
82667f8aa8f5abceedbb599ef69af1dfbb38c0df2660Slawomir Cygan            }
82677f8aa8f5abceedbb599ef69af1dfbb38c0df2660Slawomir Cygan        }
82687f8aa8f5abceedbb599ef69af1dfbb38c0df2660Slawomir Cygan    }
82697f8aa8f5abceedbb599ef69af1dfbb38c0df2660Slawomir Cygan
8270777507259dcf34d32d0cb1f6820583455a4a8377Cort    return skip;
82717f8aa8f5abceedbb599ef69af1dfbb38c0df2660Slawomir Cygan}
82727f8aa8f5abceedbb599ef69af1dfbb38c0df2660Slawomir Cygan
82739ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano// Test if two VkExtent3D structs are equivalent
82749ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitranostatic inline bool IsExtentEqual(const VkExtent3D *extent, const VkExtent3D *other_extent) {
82759ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano    bool result = true;
82769ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano    if ((extent->width != other_extent->width) || (extent->height != other_extent->height) ||
82779ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano        (extent->depth != other_extent->depth)) {
82789ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano        result = false;
82799ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano    }
82809ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano    return result;
82819ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano}
82829ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano
82839ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano// Returns the image extent of a specific subresource.
82841facd2c91911508b9fb61f54a56269841299f663Tobin Ehlisstatic inline VkExtent3D GetImageSubresourceExtent(const IMAGE_STATE *img, const VkImageSubresourceLayers *subresource) {
82859ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano    const uint32_t mip = subresource->mipLevel;
82869ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano    VkExtent3D extent = img->createInfo.extent;
828790b7c8c094c263b33382ff4756f2a23f484e8400Gregory Mitrano    extent.width = std::max(1U, extent.width >> mip);
828890b7c8c094c263b33382ff4756f2a23f484e8400Gregory Mitrano    extent.height = std::max(1U, extent.height >> mip);
828990b7c8c094c263b33382ff4756f2a23f484e8400Gregory Mitrano    extent.depth = std::max(1U, extent.depth >> mip);
82909ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano    return extent;
82919ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano}
82929ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano
82939ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano// Test if the extent argument has all dimensions set to 0.
82949ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitranostatic inline bool IsExtentZero(const VkExtent3D *extent) {
82959ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano    return ((extent->width == 0) && (extent->height == 0) && (extent->depth == 0));
82969ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano}
82979ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano
82989ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano// Returns the image transfer granularity for a specific image scaled by compressed block size if necessary.
82991facd2c91911508b9fb61f54a56269841299f663Tobin Ehlisstatic inline VkExtent3D GetScaledItg(layer_data *dev_data, const GLOBAL_CB_NODE *cb_node, const IMAGE_STATE *img) {
83009ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano    // Default to (0, 0, 0) granularity in case we can't find the real granularity for the physical device.
8301bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    VkExtent3D granularity = {0, 0, 0};
8302f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski    auto pPool = getCommandPoolNode(dev_data, cb_node->createInfo.commandPool);
8303f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski    if (pPool) {
83049ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano        granularity = dev_data->phys_dev_properties.queue_family_properties[pPool->queueFamilyIndex].minImageTransferGranularity;
83059ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano        if (vk_format_is_compressed(img->createInfo.format)) {
83069ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano            auto block_size = vk_format_compressed_block_size(img->createInfo.format);
83079ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano            granularity.width *= block_size.width;
83089ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano            granularity.height *= block_size.height;
8309f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski        }
8310f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski    }
83119ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano    return granularity;
83129ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano}
83139ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano
83149ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano// Test elements of a VkExtent3D structure against alignment constraints contained in another VkExtent3D structure
83159ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitranostatic inline bool IsExtentAligned(const VkExtent3D *extent, const VkExtent3D *granularity) {
83169ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano    bool valid = true;
83179ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano    if ((vk_safe_modulo(extent->depth, granularity->depth) != 0) || (vk_safe_modulo(extent->width, granularity->width) != 0) ||
83189ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano        (vk_safe_modulo(extent->height, granularity->height) != 0)) {
83199ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano        valid = false;
83209ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano    }
8321f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski    return valid;
8322f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski}
8323f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski
8324f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski// Check elements of a VkOffset3D structure against a queue family's Image Transfer Granularity values
83259ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitranostatic inline bool CheckItgOffset(layer_data *dev_data, const GLOBAL_CB_NODE *cb_node, const VkOffset3D *offset,
83269ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                                  const VkExtent3D *granularity, const uint32_t i, const char *function, const char *member) {
8327f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski    bool skip = false;
83289ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano    VkExtent3D offset_extent = {};
83299ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano    offset_extent.width = static_cast<uint32_t>(abs(offset->x));
83309ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano    offset_extent.height = static_cast<uint32_t>(abs(offset->y));
83319ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano    offset_extent.depth = static_cast<uint32_t>(abs(offset->z));
83329ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano    if (IsExtentZero(granularity)) {
83339ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano        // If the queue family image transfer granularity is (0, 0, 0), then the offset must always be (0, 0, 0)
83349ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano        if (IsExtentZero(&offset_extent) == false) {
83359ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
83369ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                            DRAWSTATE_IMAGE_TRANSFER_GRANULARITY, "DS",
83379ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                            "%s: pRegion[%d].%s (x=%d, y=%d, z=%d) must be (x=0, y=0, z=0) "
83389ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                            "when the command buffer's queue family image transfer granularity is (w=0, h=0, d=0).",
83399ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                            function, i, member, offset->x, offset->y, offset->z);
83409ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano        }
83419ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano    } else {
83429ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano        // If the queue family image transfer granularity is not (0, 0, 0), then the offset dimensions must always be even
83439ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano        // integer multiples of the image transfer granularity.
83449ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano        if (IsExtentAligned(&offset_extent, granularity) == false) {
83459ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
83469ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                            DRAWSTATE_IMAGE_TRANSFER_GRANULARITY, "DS",
83479ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                            "%s: pRegion[%d].%s (x=%d, y=%d, z=%d) dimensions must be even integer "
83489ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                            "multiples of this command buffer's queue family image transfer granularity (w=%d, h=%d, d=%d).",
83499ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                            function, i, member, offset->x, offset->y, offset->z, granularity->width, granularity->height,
83509ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                            granularity->depth);
83519ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano        }
8352f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski    }
8353f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski    return skip;
8354f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski}
8355f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski
8356f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski// Check elements of a VkExtent3D structure against a queue family's Image Transfer Granularity values
83579ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitranostatic inline bool CheckItgExtent(layer_data *dev_data, const GLOBAL_CB_NODE *cb_node, const VkExtent3D *extent,
83589ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                                  const VkOffset3D *offset, const VkExtent3D *granularity, const VkExtent3D *subresource_extent,
83599ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                                  const uint32_t i, const char *function, const char *member) {
8360f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski    bool skip = false;
83619ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano    if (IsExtentZero(granularity)) {
83629ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano        // If the queue family image transfer granularity is (0, 0, 0), then the extent must always match the image
83639ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano        // subresource extent.
83649ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano        if (IsExtentEqual(extent, subresource_extent) == false) {
83659ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
83669ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                            DRAWSTATE_IMAGE_TRANSFER_GRANULARITY, "DS",
83679ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                            "%s: pRegion[%d].%s (w=%d, h=%d, d=%d) must match the image subresource extents (w=%d, h=%d, d=%d) "
83689ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                            "when the command buffer's queue family image transfer granularity is (w=0, h=0, d=0).",
83699ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                            function, i, member, extent->width, extent->height, extent->depth, subresource_extent->width,
83709ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                            subresource_extent->height, subresource_extent->depth);
83719ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano        }
83729ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano    } else {
83739ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano        // If the queue family image transfer granularity is not (0, 0, 0), then the extent dimensions must always be even
83749ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano        // integer multiples of the image transfer granularity or the offset + extent dimensions must always match the image
83759ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano        // subresource extent dimensions.
83769ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano        VkExtent3D offset_extent_sum = {};
83779ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano        offset_extent_sum.width = static_cast<uint32_t>(abs(offset->x)) + extent->width;
83789ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano        offset_extent_sum.height = static_cast<uint32_t>(abs(offset->y)) + extent->height;
83799ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano        offset_extent_sum.depth = static_cast<uint32_t>(abs(offset->z)) + extent->depth;
83809ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano        if ((IsExtentAligned(extent, granularity) == false) && (IsExtentEqual(&offset_extent_sum, subresource_extent) == false)) {
83819ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano            skip |=
83829ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8383f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski                        DRAWSTATE_IMAGE_TRANSFER_GRANULARITY, "DS",
83849ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                        "%s: pRegion[%d].%s (w=%d, h=%d, d=%d) dimensions must be even integer multiples of this command buffer's "
83859ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                        "queue family image transfer granularity (w=%d, h=%d, d=%d) or offset (x=%d, y=%d, z=%d) + "
83869ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                        "extent (w=%d, h=%d, d=%d) must match the image subresource extents (w=%d, h=%d, d=%d).",
83879ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                        function, i, member, extent->width, extent->height, extent->depth, granularity->width, granularity->height,
83889ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                        granularity->depth, offset->x, offset->y, offset->z, extent->width, extent->height, extent->depth,
83899ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                        subresource_extent->width, subresource_extent->height, subresource_extent->depth);
83909ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano        }
8391f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski    }
8392f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski    return skip;
8393f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski}
8394f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski
8395f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski// Check a uint32_t width or stride value against a queue family's Image Transfer Granularity width value
83969ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitranostatic inline bool CheckItgInt(layer_data *dev_data, const GLOBAL_CB_NODE *cb_node, const uint32_t value,
83979ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                               const uint32_t granularity, const uint32_t i, const char *function, const char *member) {
8398f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski    bool skip = false;
83999ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano    if (vk_safe_modulo(value, granularity) != 0) {
8400f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8401f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski                        DRAWSTATE_IMAGE_TRANSFER_GRANULARITY, "DS",
84029ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                        "%s: pRegion[%d].%s (%d) must be an even integer multiple of this command buffer's queue family image "
84039ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                        "transfer granularity width (%d).",
84049ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                        function, i, member, value, granularity);
8405f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski    }
8406f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski    return skip;
8407f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski}
8408f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski
8409f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski// Check a VkDeviceSize value against a queue family's Image Transfer Granularity width value
84109ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitranostatic inline bool CheckItgSize(layer_data *dev_data, const GLOBAL_CB_NODE *cb_node, const VkDeviceSize value,
84119ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                                const uint32_t granularity, const uint32_t i, const char *function, const char *member) {
8412f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski    bool skip = false;
84139ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano    if (vk_safe_modulo(value, granularity) != 0) {
84149ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
84159ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                        DRAWSTATE_IMAGE_TRANSFER_GRANULARITY, "DS",
84169ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                        "%s: pRegion[%d].%s (%" PRIdLEAST64
84179ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                        ") must be an even integer multiple of this command buffer's queue family image transfer "
84189ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                        "granularity width (%d).",
84199ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                        function, i, member, value, granularity);
8420f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski    }
8421f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski    return skip;
8422f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski}
8423f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski
8424f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski// Check valid usage Image Tranfer Granularity requirements for elements of a VkImageCopy structure
8425f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinskistatic inline bool ValidateCopyImageTransferGranularityRequirements(layer_data *dev_data, const GLOBAL_CB_NODE *cb_node,
84261facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis                                                                    const IMAGE_STATE *img, const VkImageCopy *region,
84279ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                                                                    const uint32_t i, const char *function) {
8428f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski    bool skip = false;
84299ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano    VkExtent3D granularity = GetScaledItg(dev_data, cb_node, img);
84309ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano    skip |= CheckItgOffset(dev_data, cb_node, &region->srcOffset, &granularity, i, function, "srcOffset");
84319ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano    skip |= CheckItgOffset(dev_data, cb_node, &region->dstOffset, &granularity, i, function, "dstOffset");
84329ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano    VkExtent3D subresource_extent = GetImageSubresourceExtent(img, &region->dstSubresource);
84339ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano    skip |= CheckItgExtent(dev_data, cb_node, &region->extent, &region->dstOffset, &granularity, &subresource_extent, i, function,
84349ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                           "extent");
8435f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski    return skip;
8436f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski}
8437f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski
8438f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski// Check valid usage Image Tranfer Granularity requirements for elements of a VkBufferImageCopy structure
8439f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinskistatic inline bool ValidateCopyBufferImageTransferGranularityRequirements(layer_data *dev_data, const GLOBAL_CB_NODE *cb_node,
84401facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis                                                                          const IMAGE_STATE *img, const VkBufferImageCopy *region,
84419ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                                                                          const uint32_t i, const char *function) {
8442f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski    bool skip = false;
8443b10e59bb49bc6bd9f35bb03363b0e9880fe8179cMark Lobodzinski    if (vk_format_is_compressed(img->createInfo.format) == true) {
8444b10e59bb49bc6bd9f35bb03363b0e9880fe8179cMark Lobodzinski        // TODO: Add granularity checking for compressed formats
8445b10e59bb49bc6bd9f35bb03363b0e9880fe8179cMark Lobodzinski
8446b10e59bb49bc6bd9f35bb03363b0e9880fe8179cMark Lobodzinski        // bufferRowLength must be a multiple of the compressed texel block width
8447b10e59bb49bc6bd9f35bb03363b0e9880fe8179cMark Lobodzinski        // bufferImageHeight must be a multiple of the compressed texel block height
8448b10e59bb49bc6bd9f35bb03363b0e9880fe8179cMark Lobodzinski        // all members of imageOffset must be a multiple of the corresponding dimensions of the compressed texel block
8449b10e59bb49bc6bd9f35bb03363b0e9880fe8179cMark Lobodzinski        // bufferOffset must be a multiple of the compressed texel block size in bytes
8450b10e59bb49bc6bd9f35bb03363b0e9880fe8179cMark Lobodzinski        // imageExtent.width must be a multiple of the compressed texel block width or (imageExtent.width + imageOffset.x)
8451b10e59bb49bc6bd9f35bb03363b0e9880fe8179cMark Lobodzinski        //     must equal the image subresource width
8452b10e59bb49bc6bd9f35bb03363b0e9880fe8179cMark Lobodzinski        // imageExtent.height must be a multiple of the compressed texel block height or (imageExtent.height + imageOffset.y)
8453b10e59bb49bc6bd9f35bb03363b0e9880fe8179cMark Lobodzinski        //     must equal the image subresource height
8454b10e59bb49bc6bd9f35bb03363b0e9880fe8179cMark Lobodzinski        // imageExtent.depth must be a multiple of the compressed texel block depth or (imageExtent.depth + imageOffset.z)
8455b10e59bb49bc6bd9f35bb03363b0e9880fe8179cMark Lobodzinski        //     must equal the image subresource depth
8456b10e59bb49bc6bd9f35bb03363b0e9880fe8179cMark Lobodzinski    } else {
8457b10e59bb49bc6bd9f35bb03363b0e9880fe8179cMark Lobodzinski        VkExtent3D granularity = GetScaledItg(dev_data, cb_node, img);
8458b10e59bb49bc6bd9f35bb03363b0e9880fe8179cMark Lobodzinski        skip |= CheckItgSize(dev_data, cb_node, region->bufferOffset, granularity.width, i, function, "bufferOffset");
8459b10e59bb49bc6bd9f35bb03363b0e9880fe8179cMark Lobodzinski        skip |= CheckItgInt(dev_data, cb_node, region->bufferRowLength, granularity.width, i, function, "bufferRowLength");
8460b10e59bb49bc6bd9f35bb03363b0e9880fe8179cMark Lobodzinski        skip |= CheckItgInt(dev_data, cb_node, region->bufferImageHeight, granularity.width, i, function, "bufferImageHeight");
8461b10e59bb49bc6bd9f35bb03363b0e9880fe8179cMark Lobodzinski        skip |= CheckItgOffset(dev_data, cb_node, &region->imageOffset, &granularity, i, function, "imageOffset");
8462b10e59bb49bc6bd9f35bb03363b0e9880fe8179cMark Lobodzinski        VkExtent3D subresource_extent = GetImageSubresourceExtent(img, &region->imageSubresource);
8463b10e59bb49bc6bd9f35bb03363b0e9880fe8179cMark Lobodzinski        skip |= CheckItgExtent(dev_data, cb_node, &region->imageExtent, &region->imageOffset, &granularity, &subresource_extent, i,
8464b10e59bb49bc6bd9f35bb03363b0e9880fe8179cMark Lobodzinski                               function, "imageExtent");
8465b10e59bb49bc6bd9f35bb03363b0e9880fe8179cMark Lobodzinski    }
8466f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski    return skip;
8467f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski}
8468f7f74f870488f026061dec2d4d3c3329a25d4dcdMark Lobodzinski
8469bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
8470bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
8471bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        const VkImageCopy *pRegions) {
847283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
84735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
8474b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
8475249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis
84769f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis    auto cb_node = getCBNode(dev_data, commandBuffer);
84771facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    auto src_image_state = getImageState(dev_data, srcImage);
84781facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    auto dst_image_state = getImageState(dev_data, dstImage);
84791facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (cb_node && src_image_state && dst_image_state) {
848035ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis        skip_call |= ValidateMemoryIsBoundToImage(dev_data, src_image_state, "vkCmdCopyImage()", VALIDATION_ERROR_02533);
848135ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis        skip_call |= ValidateMemoryIsBoundToImage(dev_data, dst_image_state, "vkCmdCopyImage()", VALIDATION_ERROR_02534);
8482249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis        // Update bindings between images and cmd buffer
84831facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        AddCommandBufferBindingImage(dev_data, cb_node, src_image_state);
84841facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        AddCommandBufferBindingImage(dev_data, cb_node, dst_image_state);
8485249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis        // Validate that SRC & DST images have correct usage flags set
84861b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes        skip_call |= ValidateImageUsageFlags(dev_data, src_image_state, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true,
84871b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes                                             VALIDATION_ERROR_01178, "vkCmdCopyImage()", "VK_IMAGE_USAGE_TRANSFER_SRC_BIT");
84881b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes        skip_call |= ValidateImageUsageFlags(dev_data, dst_image_state, VK_IMAGE_USAGE_TRANSFER_DST_BIT, true,
84891b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes                                             VALIDATION_ERROR_01181, "vkCmdCopyImage()", "VK_IMAGE_USAGE_TRANSFER_DST_BIT");
84901facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        std::function<bool()> function = [=]() {
84911facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            return ValidateImageMemoryIsValid(dev_data, src_image_state, "vkCmdCopyImage()");
84921facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        };
84939f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
8494593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        function = [=]() {
84951facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            SetImageMemoryValid(dev_data, dst_image_state, true);
8496e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
84975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        };
84989f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
8499593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
850029f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, cb_node, CMD_COPYIMAGE, "vkCmdCopyImage()");
850129f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        UpdateCmdBufferLastCmd(dev_data, cb_node, CMD_COPYIMAGE);
8502ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen        skip_call |= insideRenderPass(dev_data, cb_node, "vkCmdCopyImage()", VALIDATION_ERROR_01194);
85035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < regionCount; ++i) {
850455eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen            skip_call |= VerifySourceImageLayout(dev_data, cb_node, srcImage, pRegions[i].srcSubresource, srcImageLayout,
850555eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                                 VALIDATION_ERROR_01180);
850655eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen            skip_call |= VerifyDestImageLayout(dev_data, cb_node, dstImage, pRegions[i].dstSubresource, dstImageLayout,
850755eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                               VALIDATION_ERROR_01183);
85081facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            skip_call |= ValidateCopyImageTransferGranularityRequirements(dev_data, cb_node, dst_image_state, &pRegions[i], i,
85099ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                                                                          "vkCmdCopyImage()");
85105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8511249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis    } else {
8512249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis        assert(0);
85135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8514b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
851583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (!skip_call)
85164a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdCopyImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
85174a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                              pRegions);
85185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
85195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8520eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski// Validate that an image's sampleCount matches the requirement for a specific API call
85211facd2c91911508b9fb61f54a56269841299f663Tobin Ehlisstatic inline bool ValidateImageSampleCount(layer_data *dev_data, IMAGE_STATE *image_state, VkSampleCountFlagBits sample_count,
852255eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                            const char *location, UNIQUE_VALIDATION_ERROR_CODE msgCode) {
8523eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski    bool skip = false;
85241facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (image_state->createInfo.samples != sample_count) {
852555eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen        skip =
852655eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
852755eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                    reinterpret_cast<uint64_t &>(image_state->image), 0, msgCode, "DS",
852855eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                    "%s for image 0x%" PRIxLEAST64 " was created with a sample count of %s but must be %s. %s", location,
852955eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                    reinterpret_cast<uint64_t &>(image_state->image), string_VkSampleCountFlagBits(image_state->createInfo.samples),
853055eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                    string_VkSampleCountFlagBits(sample_count), validation_error_map[msgCode]);
8531eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski    }
8532eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski    return skip;
8533eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski}
8534eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski
8535bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
8536bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
8537bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        const VkImageBlit *pRegions, VkFilter filter) {
853883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
85395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
8540b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
8541593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
85429f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis    auto cb_node = getCBNode(dev_data, commandBuffer);
85431facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    auto src_image_state = getImageState(dev_data, srcImage);
85441facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    auto dst_image_state = getImageState(dev_data, dstImage);
85451facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (cb_node && src_image_state && dst_image_state) {
854655eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen        skip_call |= ValidateImageSampleCount(dev_data, src_image_state, VK_SAMPLE_COUNT_1_BIT, "vkCmdBlitImage(): srcImage",
854755eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                              VALIDATION_ERROR_02194);
854855eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen        skip_call |= ValidateImageSampleCount(dev_data, dst_image_state, VK_SAMPLE_COUNT_1_BIT, "vkCmdBlitImage(): dstImage",
854955eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                              VALIDATION_ERROR_02195);
855035ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis        skip_call |= ValidateMemoryIsBoundToImage(dev_data, src_image_state, "vkCmdBlitImage()", VALIDATION_ERROR_02539);
855135ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis        skip_call |= ValidateMemoryIsBoundToImage(dev_data, dst_image_state, "vkCmdBlitImage()", VALIDATION_ERROR_02540);
8552249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis        // Update bindings between images and cmd buffer
85531facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        AddCommandBufferBindingImage(dev_data, cb_node, src_image_state);
85541facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        AddCommandBufferBindingImage(dev_data, cb_node, dst_image_state);
8555249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis        // Validate that SRC & DST images have correct usage flags set
85561b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes        skip_call |= ValidateImageUsageFlags(dev_data, src_image_state, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true,
85571b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes                                             VALIDATION_ERROR_02182, "vkCmdBlitImage()", "VK_IMAGE_USAGE_TRANSFER_SRC_BIT");
85581b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes        skip_call |= ValidateImageUsageFlags(dev_data, dst_image_state, VK_IMAGE_USAGE_TRANSFER_DST_BIT, true,
85591b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes                                             VALIDATION_ERROR_02186, "vkCmdBlitImage()", "VK_IMAGE_USAGE_TRANSFER_DST_BIT");
85601facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        std::function<bool()> function = [=]() {
85611facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            return ValidateImageMemoryIsValid(dev_data, src_image_state, "vkCmdBlitImage()");
85621facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        };
85639f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
8564593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        function = [=]() {
85651facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            SetImageMemoryValid(dev_data, dst_image_state, true);
8566e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
85675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        };
85689f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
8569593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
857029f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, cb_node, CMD_BLITIMAGE, "vkCmdBlitImage()");
857129f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        UpdateCmdBufferLastCmd(dev_data, cb_node, CMD_BLITIMAGE);
8572ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen        skip_call |= insideRenderPass(dev_data, cb_node, "vkCmdBlitImage()", VALIDATION_ERROR_01300);
8573249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis    } else {
8574249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis        assert(0);
85755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8576b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
857783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (!skip_call)
85784a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdBlitImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
85794a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                              pRegions, filter);
85805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
85815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8582bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage,
8583bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                VkImageLayout dstImageLayout, uint32_t regionCount,
8584bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkBufferImageCopy *pRegions) {
858583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
85865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
8587b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
8588593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
85899f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis    auto cb_node = getCBNode(dev_data, commandBuffer);
85905cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    auto src_buff_state = getBufferState(dev_data, srcBuffer);
85911facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    auto dst_image_state = getImageState(dev_data, dstImage);
85925cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (cb_node && src_buff_state && dst_image_state) {
859355eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen        skip_call |= ValidateImageSampleCount(dev_data, dst_image_state, VK_SAMPLE_COUNT_1_BIT,
859455eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                              "vkCmdCopyBufferToImage(): dstImage", VALIDATION_ERROR_01232);
859535ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis        skip_call |= ValidateMemoryIsBoundToBuffer(dev_data, src_buff_state, "vkCmdCopyBufferToImage()", VALIDATION_ERROR_02535);
859635ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis        skip_call |= ValidateMemoryIsBoundToImage(dev_data, dst_image_state, "vkCmdCopyBufferToImage()", VALIDATION_ERROR_02536);
85975cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        AddCommandBufferBindingBuffer(dev_data, cb_node, src_buff_state);
85981facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        AddCommandBufferBindingImage(dev_data, cb_node, dst_image_state);
85991b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes        skip_call |=
86005cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            ValidateBufferUsageFlags(dev_data, src_buff_state, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, true, VALIDATION_ERROR_01230,
86011b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes                                     "vkCmdCopyBufferToImage()", "VK_BUFFER_USAGE_TRANSFER_SRC_BIT");
86021facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        skip_call |= ValidateImageUsageFlags(dev_data, dst_image_state, VK_IMAGE_USAGE_TRANSFER_DST_BIT, true,
86031b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes                                             VALIDATION_ERROR_01231, "vkCmdCopyBufferToImage()", "VK_IMAGE_USAGE_TRANSFER_DST_BIT");
8604e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
86051facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            SetImageMemoryValid(dev_data, dst_image_state, true);
8606e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
86075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        };
86089f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
86095cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        function = [=]() { return ValidateBufferMemoryIsValid(dev_data, src_buff_state, "vkCmdCopyBufferToImage()"); };
86109f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
8611593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
861229f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, cb_node, CMD_COPYBUFFERTOIMAGE, "vkCmdCopyBufferToImage()");
861329f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        UpdateCmdBufferLastCmd(dev_data, cb_node, CMD_COPYBUFFERTOIMAGE);
8614ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen        skip_call |= insideRenderPass(dev_data, cb_node, "vkCmdCopyBufferToImage()", VALIDATION_ERROR_01242);
86155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < regionCount; ++i) {
861655eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen            skip_call |= VerifyDestImageLayout(dev_data, cb_node, dstImage, pRegions[i].imageSubresource, dstImageLayout,
861755eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                               VALIDATION_ERROR_01234);
86181facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            skip_call |= ValidateCopyBufferImageTransferGranularityRequirements(dev_data, cb_node, dst_image_state, &pRegions[i], i,
86199ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                                                                                "vkCmdCopyBufferToImage()");
86205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8621ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
8622ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
86235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8624b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
862583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (!skip_call)
86264a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdCopyBufferToImage(commandBuffer, srcBuffer, dstImage, dstImageLayout, regionCount, pRegions);
86275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
86285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8629bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
8630bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy *pRegions) {
863183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
86325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
8633b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
8634593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
86359f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis    auto cb_node = getCBNode(dev_data, commandBuffer);
86361facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    auto src_image_state = getImageState(dev_data, srcImage);
86375cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    auto dst_buff_state = getBufferState(dev_data, dstBuffer);
86385cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (cb_node && src_image_state && dst_buff_state) {
863955eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen        skip_call |= ValidateImageSampleCount(dev_data, src_image_state, VK_SAMPLE_COUNT_1_BIT,
864055eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                              "vkCmdCopyImageToBuffer(): srcImage", VALIDATION_ERROR_01249);
864135ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis        skip_call |= ValidateMemoryIsBoundToImage(dev_data, src_image_state, "vkCmdCopyImageToBuffer()", VALIDATION_ERROR_02537);
864235ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis        skip_call |= ValidateMemoryIsBoundToBuffer(dev_data, dst_buff_state, "vkCmdCopyImageToBuffer()", VALIDATION_ERROR_02538);
8643249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis        // Update bindings between buffer/image and cmd buffer
86441facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        AddCommandBufferBindingImage(dev_data, cb_node, src_image_state);
86455cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        AddCommandBufferBindingBuffer(dev_data, cb_node, dst_buff_state);
8646249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis        // Validate that SRC image & DST buffer have correct usage flags set
86471facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        skip_call |= ValidateImageUsageFlags(dev_data, src_image_state, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true,
86481b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes                                             VALIDATION_ERROR_01248, "vkCmdCopyImageToBuffer()", "VK_IMAGE_USAGE_TRANSFER_SRC_BIT");
86491b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes        skip_call |=
86505cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            ValidateBufferUsageFlags(dev_data, dst_buff_state, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, VALIDATION_ERROR_01252,
86511b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes                                     "vkCmdCopyImageToBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
8652e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
86531facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            return ValidateImageMemoryIsValid(dev_data, src_image_state, "vkCmdCopyImageToBuffer()");
8654e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        };
86559f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
8656593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        function = [=]() {
86575cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            SetBufferMemoryValid(dev_data, dst_buff_state, true);
8658e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
86595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        };
86609f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
8661593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
866229f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, cb_node, CMD_COPYIMAGETOBUFFER, "vkCmdCopyImageToBuffer()");
866329f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        UpdateCmdBufferLastCmd(dev_data, cb_node, CMD_COPYIMAGETOBUFFER);
8664ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen        skip_call |= insideRenderPass(dev_data, cb_node, "vkCmdCopyImageToBuffer()", VALIDATION_ERROR_01260);
86655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < regionCount; ++i) {
866655eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen            skip_call |= VerifySourceImageLayout(dev_data, cb_node, srcImage, pRegions[i].imageSubresource, srcImageLayout,
866755eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                                 VALIDATION_ERROR_01251);
86681facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            skip_call |= ValidateCopyBufferImageTransferGranularityRequirements(dev_data, cb_node, src_image_state, &pRegions[i], i,
86699ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                                                                                "CmdCopyImageToBuffer");
86705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8671ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
8672ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
86735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8674b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
867583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (!skip_call)
86764a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdCopyImageToBuffer(commandBuffer, srcImage, srcImageLayout, dstBuffer, regionCount, pRegions);
86775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
86785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8679bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
8680bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           VkDeviceSize dataSize, const uint32_t *pData) {
868183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
86825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
8683b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
8684593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
86859f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis    auto cb_node = getCBNode(dev_data, commandBuffer);
86865cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    auto dst_buff_state = getBufferState(dev_data, dstBuffer);
86875cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (cb_node && dst_buff_state) {
868835ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis        skip_call |= ValidateMemoryIsBoundToBuffer(dev_data, dst_buff_state, "vkCmdUpdateBuffer()", VALIDATION_ERROR_02530);
8689ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Update bindings between buffer and cmd buffer
86905cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        AddCommandBufferBindingBuffer(dev_data, cb_node, dst_buff_state);
8691ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Validate that DST buffer has correct usage flags set
86925cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        skip_call |= ValidateBufferUsageFlags(dev_data, dst_buff_state, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true,
86931b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes                                              VALIDATION_ERROR_01146, "vkCmdUpdateBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
8694e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
86955cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            SetBufferMemoryValid(dev_data, dst_buff_state, true);
8696e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
86975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        };
86989f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
8699593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
870029f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, cb_node, CMD_UPDATEBUFFER, "vkCmdUpdateBuffer()");
870129f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        UpdateCmdBufferLastCmd(dev_data, cb_node, CMD_UPDATEBUFFER);
8702ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen        skip_call |= insideRenderPass(dev_data, cb_node, "vkCmdUpdateBuffer()", VALIDATION_ERROR_01155);
8703ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
8704ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
87055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8706b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8707cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdUpdateBuffer(commandBuffer, dstBuffer, dstOffset, dataSize, pData);
87085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
87095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8710bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
8711bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         VkDeviceSize size, uint32_t data) {
871283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
87135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
8714b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
8715593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
87169f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis    auto cb_node = getCBNode(dev_data, commandBuffer);
87175cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    auto dst_buff_state = getBufferState(dev_data, dstBuffer);
87185cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (cb_node && dst_buff_state) {
871935ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis        skip_call |= ValidateMemoryIsBoundToBuffer(dev_data, dst_buff_state, "vkCmdFillBuffer()", VALIDATION_ERROR_02529);
8720ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Update bindings between buffer and cmd buffer
87215cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        AddCommandBufferBindingBuffer(dev_data, cb_node, dst_buff_state);
8722ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Validate that DST buffer has correct usage flags set
87235cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        skip_call |= ValidateBufferUsageFlags(dev_data, dst_buff_state, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true,
87241b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes                                              VALIDATION_ERROR_01137, "vkCmdFillBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
8725e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
87265cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            SetBufferMemoryValid(dev_data, dst_buff_state, true);
8727e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
87285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        };
87299f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
8730593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
873129f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, cb_node, CMD_FILLBUFFER, "vkCmdFillBuffer()");
873229f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        UpdateCmdBufferLastCmd(dev_data, cb_node, CMD_FILLBUFFER);
8733ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen        skip_call |= insideRenderPass(dev_data, cb_node, "vkCmdFillBuffer()", VALIDATION_ERROR_01142);
8734ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
8735ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
87365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8737b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8738cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdFillBuffer(commandBuffer, dstBuffer, dstOffset, size, data);
87395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
87405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
874140a76588a6e9dd44901c769166983c0abec51aa3Mark Lobodzinski// Returns true if sub_rect is entirely contained within rect
874240a76588a6e9dd44901c769166983c0abec51aa3Mark Lobodzinskistatic inline bool ContainsRect(VkRect2D rect, VkRect2D sub_rect) {
8743bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    if ((sub_rect.offset.x < rect.offset.x) || (sub_rect.offset.x + sub_rect.extent.width > rect.offset.x + rect.extent.width) ||
8744bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        (sub_rect.offset.y < rect.offset.y) || (sub_rect.offset.y + sub_rect.extent.height > rect.offset.y + rect.extent.height))
874540a76588a6e9dd44901c769166983c0abec51aa3Mark Lobodzinski        return false;
874640a76588a6e9dd44901c769166983c0abec51aa3Mark Lobodzinski    return true;
874740a76588a6e9dd44901c769166983c0abec51aa3Mark Lobodzinski}
874840a76588a6e9dd44901c769166983c0abec51aa3Mark Lobodzinski
87494028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinskibool PreCallValidateCmdClearAttachments(layer_data *dev_data, VkCommandBuffer commandBuffer, uint32_t attachmentCount,
87504028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski                                        const VkClearAttachment *pAttachments, uint32_t rectCount, const VkClearRect *pRects) {
8751f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski    GLOBAL_CB_NODE *cb_node = getCBNode(dev_data, commandBuffer);
87524028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski    bool skip = false;
8753f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski    if (cb_node) {
8754f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_node, CMD_CLEARATTACHMENTS, "vkCmdClearAttachments()");
8755f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski        UpdateCmdBufferLastCmd(dev_data, cb_node, CMD_CLEARATTACHMENTS);
87565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Warn if this is issued prior to Draw Cmd and clearing the entire attachment
8757f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski        if (!hasDrawCmd(cb_node) && (cb_node->activeRenderPassBeginInfo.renderArea.extent.width == pRects[0].rect.extent.width) &&
8758f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski            (cb_node->activeRenderPassBeginInfo.renderArea.extent.height == pRects[0].rect.extent.height)) {
87595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // There are times where app needs to use ClearAttachments (generally when reusing a buffer inside of a render pass)
87605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // 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
8761f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski            // call CmdClearAttachments. Otherwise this seems more like a performance warning.
8762f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
8763f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski                            VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t &>(commandBuffer), 0,
8764f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski                            DRAWSTATE_CLEAR_CMD_BEFORE_DRAW, "DS",
8765f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski                            "vkCmdClearAttachments() issued on command buffer object 0x%p prior to any Draw Cmds."
8766f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski                            " It is recommended you use RenderPass LOAD_OP_CLEAR on Attachments prior to any Draw.",
8767f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski                            commandBuffer);
87685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8769f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski        skip |= outsideRenderPass(dev_data, cb_node, "vkCmdClearAttachments()", VALIDATION_ERROR_01122);
87705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
87715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
87725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Validate that attachment is in reference list of active subpass
8773f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski    if (cb_node->activeRenderPass) {
8774f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski        const VkRenderPassCreateInfo *renderpass_create_info = cb_node->activeRenderPass->createInfo.ptr();
8775f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski        const VkSubpassDescription *subpass_desc = &renderpass_create_info->pSubpasses[cb_node->activeSubpass];
8776f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski        auto framebuffer = getFramebufferState(dev_data, cb_node->activeFramebuffer);
87775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
877871bd13d45fa6d188e8f6ff9c0302aa0514c6ff2aChris Forbes        for (uint32_t i = 0; i < attachmentCount; i++) {
877971bd13d45fa6d188e8f6ff9c0302aa0514c6ff2aChris Forbes            auto clear_desc = &pAttachments[i];
8780932099bcf863cd3cffc0d779a01710a4d28b4c52Chris Forbes            VkImageView image_view = VK_NULL_HANDLE;
8781932099bcf863cd3cffc0d779a01710a4d28b4c52Chris Forbes
878271bd13d45fa6d188e8f6ff9c0302aa0514c6ff2aChris Forbes            if (clear_desc->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
8783f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski                if (clear_desc->colorAttachment >= subpass_desc->colorAttachmentCount) {
8784f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski                    skip |= log_msg(
878521a714edaf9b670a60102430c36b221ff27f0f25Chris Forbes                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
8786e9005417571718f4a3c114929e12cb9d088443a2Chris Forbes                        (uint64_t)commandBuffer, __LINE__, VALIDATION_ERROR_01114, "DS",
8787e9005417571718f4a3c114929e12cb9d088443a2Chris Forbes                        "vkCmdClearAttachments() color attachment index %d out of range for active subpass %d. %s",
8788f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski                        clear_desc->colorAttachment, cb_node->activeSubpass, validation_error_map[VALIDATION_ERROR_01114]);
8789f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski                } else if (subpass_desc->pColorAttachments[clear_desc->colorAttachment].attachment == VK_ATTACHMENT_UNUSED) {
8790f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
8791f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski                                    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)commandBuffer, __LINE__,
8792f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski                                    DRAWSTATE_MISSING_ATTACHMENT_REFERENCE, "DS",
8793f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski                                    "vkCmdClearAttachments() color attachment index %d is VK_ATTACHMENT_UNUSED; ignored.",
8794f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski                                    clear_desc->colorAttachment);
879540a76588a6e9dd44901c769166983c0abec51aa3Mark Lobodzinski                } else {
8796f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski                    image_view = framebuffer->createInfo
8797f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski                                     .pAttachments[subpass_desc->pColorAttachments[clear_desc->colorAttachment].attachment];
8798932099bcf863cd3cffc0d779a01710a4d28b4c52Chris Forbes                }
879971bd13d45fa6d188e8f6ff9c0302aa0514c6ff2aChris Forbes            } else if (clear_desc->aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
8800cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (!subpass_desc->pDepthStencilAttachment ||  // Says no DS will be used in active subpass
8801f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski                    (subpass_desc->pDepthStencilAttachment->attachment ==
8802cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                     VK_ATTACHMENT_UNUSED)) {  // Says no DS will be used in active subpass
88035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8804f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski                    skip |=
880540a76588a6e9dd44901c769166983c0abec51aa3Mark Lobodzinski                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
880640a76588a6e9dd44901c769166983c0abec51aa3Mark Lobodzinski                                VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)commandBuffer, __LINE__,
880740a76588a6e9dd44901c769166983c0abec51aa3Mark Lobodzinski                                DRAWSTATE_MISSING_ATTACHMENT_REFERENCE, "DS",
880840a76588a6e9dd44901c769166983c0abec51aa3Mark Lobodzinski                                "vkCmdClearAttachments() depth/stencil clear with no depth/stencil attachment in subpass; ignored");
880940a76588a6e9dd44901c769166983c0abec51aa3Mark Lobodzinski                } else {
8810f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski                    image_view = framebuffer->createInfo.pAttachments[subpass_desc->pDepthStencilAttachment->attachment];
8811932099bcf863cd3cffc0d779a01710a4d28b4c52Chris Forbes                }
8812932099bcf863cd3cffc0d779a01710a4d28b4c52Chris Forbes            }
8813932099bcf863cd3cffc0d779a01710a4d28b4c52Chris Forbes
8814932099bcf863cd3cffc0d779a01710a4d28b4c52Chris Forbes            if (image_view) {
8815932099bcf863cd3cffc0d779a01710a4d28b4c52Chris Forbes                auto image_view_state = getImageViewState(dev_data, image_view);
881640a76588a6e9dd44901c769166983c0abec51aa3Mark Lobodzinski                for (uint32_t j = 0; j < rectCount; j++) {
881740a76588a6e9dd44901c769166983c0abec51aa3Mark Lobodzinski                    // The rectangular region specified by a given element of pRects must be contained within the render area of the
881840a76588a6e9dd44901c769166983c0abec51aa3Mark Lobodzinski                    // current render pass instance
8819f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski                    if (false == ContainsRect(cb_node->activeRenderPassBeginInfo.renderArea, pRects[j].rect)) {
8820f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski                        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
8821f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski                                        VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, VALIDATION_ERROR_01115, "DS",
8822f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski                                        "vkCmdClearAttachments(): The area defined by pRects[%d] is not contained in the area of "
8823f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski                                        "the current render pass instance. %s",
8824f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski                                        j, validation_error_map[VALIDATION_ERROR_01115]);
882540a76588a6e9dd44901c769166983c0abec51aa3Mark Lobodzinski                    }
882640a76588a6e9dd44901c769166983c0abec51aa3Mark Lobodzinski                    // The layers specified by a given element of pRects must be contained within every attachment that
882740a76588a6e9dd44901c769166983c0abec51aa3Mark Lobodzinski                    // pAttachments refers to
882840a76588a6e9dd44901c769166983c0abec51aa3Mark Lobodzinski                    auto attachment_base_array_layer = image_view_state->create_info.subresourceRange.baseArrayLayer;
882940a76588a6e9dd44901c769166983c0abec51aa3Mark Lobodzinski                    auto attachment_layer_count = image_view_state->create_info.subresourceRange.layerCount;
883040a76588a6e9dd44901c769166983c0abec51aa3Mark Lobodzinski                    if ((pRects[j].baseArrayLayer < attachment_base_array_layer) || pRects[j].layerCount > attachment_layer_count) {
8831f72f8ce7e4dc62b19ebe25d3f55cfa5cbf1f5d5eMark Lobodzinski                        skip |=
883240a76588a6e9dd44901c769166983c0abec51aa3Mark Lobodzinski                            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
883340a76588a6e9dd44901c769166983c0abec51aa3Mark Lobodzinski                                    0, __LINE__, VALIDATION_ERROR_01116, "DS",
883440a76588a6e9dd44901c769166983c0abec51aa3Mark Lobodzinski                                    "vkCmdClearAttachments(): The layers defined in pRects[%d] are not contained in the layers of "
883540a76588a6e9dd44901c769166983c0abec51aa3Mark Lobodzinski                                    "pAttachment[%d]. %s",
883640a76588a6e9dd44901c769166983c0abec51aa3Mark Lobodzinski                                    j, i, validation_error_map[VALIDATION_ERROR_01116]);
883740a76588a6e9dd44901c769166983c0abec51aa3Mark Lobodzinski                    }
8838932099bcf863cd3cffc0d779a01710a4d28b4c52Chris Forbes                }
88395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
88405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
88415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
88424028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski    return skip;
88434028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski}
88444028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski
88454028af23e688ab5730f48ab2244dd042e2eefaedMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount,
88464028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski                                               const VkClearAttachment *pAttachments, uint32_t rectCount,
88474028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski                                               const VkClearRect *pRects) {
88484028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski    bool skip = false;
88494028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
88504028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski    {
88514028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski        std::lock_guard<std::mutex> lock(global_lock);
88524028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski        skip = PreCallValidateCmdClearAttachments(dev_data, commandBuffer, attachmentCount, pAttachments, rectCount, pRects);
88534028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski    }
8854cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdClearAttachments(commandBuffer, attachmentCount, pAttachments, rectCount, pRects);
88555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
88565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8857bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
8858bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              const VkClearColorValue *pColor, uint32_t rangeCount,
8859bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              const VkImageSubresourceRange *pRanges) {
886083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
88615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
8862b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
88635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO : Verify memory is in VK_IMAGE_STATE_CLEAR state
8864249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis
88659f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis    auto cb_node = getCBNode(dev_data, commandBuffer);
88661facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    auto image_state = getImageState(dev_data, image);
88671facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (cb_node && image_state) {
886835ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis        skip_call |= ValidateMemoryIsBoundToImage(dev_data, image_state, "vkCmdClearColorImage()", VALIDATION_ERROR_02527);
88691facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        AddCommandBufferBindingImage(dev_data, cb_node, image_state);
8870e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
88711facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            SetImageMemoryValid(dev_data, image_state, true);
8872e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
88735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        };
88749f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
8875593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
887629f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, cb_node, CMD_CLEARCOLORIMAGE, "vkCmdClearColorImage()");
887729f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        UpdateCmdBufferLastCmd(dev_data, cb_node, CMD_CLEARCOLORIMAGE);
8878ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen        skip_call |= insideRenderPass(dev_data, cb_node, "vkCmdClearColorImage()", VALIDATION_ERROR_01096);
8879249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis    } else {
8880249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis        assert(0);
88815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
88827f8aa8f5abceedbb599ef69af1dfbb38c0df2660Slawomir Cygan    for (uint32_t i = 0; i < rangeCount; ++i) {
88831c2dd65baf29dba7c39172cf25f296a25baa4f3aCort        skip_call |= VerifyClearImageLayout(dev_data, cb_node, image, pRanges[i], imageLayout, "vkCmdClearColorImage()");
88847f8aa8f5abceedbb599ef69af1dfbb38c0df2660Slawomir Cygan    }
8885b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8886cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdClearColorImage(commandBuffer, image, imageLayout, pColor, rangeCount, pRanges);
88875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
88885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8889bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
8890bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                     const VkClearDepthStencilValue *pDepthStencil, uint32_t rangeCount,
8891bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                     const VkImageSubresourceRange *pRanges) {
889283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
88935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
8894b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
88955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO : Verify memory is in VK_IMAGE_STATE_CLEAR state
8896249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis
88979f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis    auto cb_node = getCBNode(dev_data, commandBuffer);
88981facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    auto image_state = getImageState(dev_data, image);
88991facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (cb_node && image_state) {
890035ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis        skip_call |= ValidateMemoryIsBoundToImage(dev_data, image_state, "vkCmdClearDepthStencilImage()", VALIDATION_ERROR_02528);
89011facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        AddCommandBufferBindingImage(dev_data, cb_node, image_state);
8902e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
89031facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            SetImageMemoryValid(dev_data, image_state, true);
8904e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
89055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        };
89069f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
8907593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
890829f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, cb_node, CMD_CLEARDEPTHSTENCILIMAGE, "vkCmdClearDepthStencilImage()");
890929f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        UpdateCmdBufferLastCmd(dev_data, cb_node, CMD_CLEARDEPTHSTENCILIMAGE);
8910ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen        skip_call |= insideRenderPass(dev_data, cb_node, "vkCmdClearDepthStencilImage()", VALIDATION_ERROR_01111);
8911249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis    } else {
8912249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis        assert(0);
89135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
89147f8aa8f5abceedbb599ef69af1dfbb38c0df2660Slawomir Cygan    for (uint32_t i = 0; i < rangeCount; ++i) {
89151c2dd65baf29dba7c39172cf25f296a25baa4f3aCort        skip_call |= VerifyClearImageLayout(dev_data, cb_node, image, pRanges[i], imageLayout, "vkCmdClearDepthStencilImage()");
89167f8aa8f5abceedbb599ef69af1dfbb38c0df2660Slawomir Cygan    }
8917b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
891883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (!skip_call)
89194a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdClearDepthStencilImage(commandBuffer, image, imageLayout, pDepthStencil, rangeCount, pRanges);
89205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
89215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8922bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
8923bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
8924bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           const VkImageResolve *pRegions) {
892583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
89265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
8927b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
8928593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
89299f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis    auto cb_node = getCBNode(dev_data, commandBuffer);
89301facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    auto src_image_state = getImageState(dev_data, srcImage);
89311facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    auto dst_image_state = getImageState(dev_data, dstImage);
89321facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (cb_node && src_image_state && dst_image_state) {
893335ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis        skip_call |= ValidateMemoryIsBoundToImage(dev_data, src_image_state, "vkCmdResolveImage()", VALIDATION_ERROR_02541);
893435ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis        skip_call |= ValidateMemoryIsBoundToImage(dev_data, dst_image_state, "vkCmdResolveImage()", VALIDATION_ERROR_02542);
8935249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis        // Update bindings between images and cmd buffer
89361facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        AddCommandBufferBindingImage(dev_data, cb_node, src_image_state);
89371facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        AddCommandBufferBindingImage(dev_data, cb_node, dst_image_state);
8938e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
89391facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            return ValidateImageMemoryIsValid(dev_data, src_image_state, "vkCmdResolveImage()");
8940593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        };
89419f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
8942593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        function = [=]() {
89431facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            SetImageMemoryValid(dev_data, dst_image_state, true);
8944e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
89455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        };
89469f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
8947593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
894829f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, cb_node, CMD_RESOLVEIMAGE, "vkCmdResolveImage()");
894929f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        UpdateCmdBufferLastCmd(dev_data, cb_node, CMD_RESOLVEIMAGE);
8950ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen        skip_call |= insideRenderPass(dev_data, cb_node, "vkCmdResolveImage()", VALIDATION_ERROR_01335);
8951249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis    } else {
8952249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis        assert(0);
89535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8954b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
895583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (!skip_call)
89564a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdResolveImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
89574a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                 pRegions);
89585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
89595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8960b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentinebool setEventStageMask(VkQueue queue, VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
8961b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
8962b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
8963b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    if (pCB) {
8964b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        pCB->eventToStageMap[event] = stageMask;
8965b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
8966b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    auto queue_data = dev_data->queueMap.find(queue);
8967b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    if (queue_data != dev_data->queueMap.end()) {
8968b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        queue_data->second.eventToStageMap[event] = stageMask;
8969b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
8970b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    return false;
8971b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine}
8972b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine
8973bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
897483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
89755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
8976b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
89775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
89785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
897929f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETEVENT, "vkCmdSetEvent()");
898029f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        UpdateCmdBufferLastCmd(dev_data, pCB, CMD_SETEVENT);
8981ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen        skip_call |= insideRenderPass(dev_data, pCB, "vkCmdSetEvent()", VALIDATION_ERROR_00238);
8982208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip_call |=
8983208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis            ValidateStageMaskGsTsEnables(dev_data, stageMask, "vkCmdSetEvent()", VALIDATION_ERROR_00230, VALIDATION_ERROR_00231);
89844710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        auto event_state = getEventNode(dev_data, event);
89854710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        if (event_state) {
89864710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis            addCommandBufferBinding(&event_state->cb_bindings,
8987ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis                                    {reinterpret_cast<uint64_t &>(event), VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT}, pCB);
89884710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis            event_state->cb_bindings.insert(pCB);
8989ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis        }
89905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->events.push_back(event);
8991c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine        if (!pCB->waitedEvents.count(event)) {
8992c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine            pCB->writeEventsBeforeWait.push_back(event);
8993c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine        }
8994b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        std::function<bool(VkQueue)> eventUpdate =
8995b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            std::bind(setEventStageMask, std::placeholders::_1, commandBuffer, event, stageMask);
8996b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        pCB->eventUpdates.push_back(eventUpdate);
89975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8998b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8999cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetEvent(commandBuffer, event, stageMask);
90005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
90015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9002bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdResetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
900383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
90045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
9005b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
90065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
90075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
900829f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_RESETEVENT, "vkCmdResetEvent()");
900929f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        UpdateCmdBufferLastCmd(dev_data, pCB, CMD_RESETEVENT);
9010ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen        skip_call |= insideRenderPass(dev_data, pCB, "vkCmdResetEvent()", VALIDATION_ERROR_00249);
9011208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip_call |=
9012208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis            ValidateStageMaskGsTsEnables(dev_data, stageMask, "vkCmdResetEvent()", VALIDATION_ERROR_00240, VALIDATION_ERROR_00241);
90134710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        auto event_state = getEventNode(dev_data, event);
90144710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        if (event_state) {
90154710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis            addCommandBufferBinding(&event_state->cb_bindings,
9016ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis                                    {reinterpret_cast<uint64_t &>(event), VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT}, pCB);
90174710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis            event_state->cb_bindings.insert(pCB);
9018ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis        }
90195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->events.push_back(event);
9020c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine        if (!pCB->waitedEvents.count(event)) {
9021c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine            pCB->writeEventsBeforeWait.push_back(event);
9022c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine        }
9023208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        // TODO : Add check for VALIDATION_ERROR_00226
9024b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        std::function<bool(VkQueue)> eventUpdate =
9025b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            std::bind(setEventStageMask, std::placeholders::_1, commandBuffer, event, VkPipelineStageFlags(0));
9026b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        pCB->eventUpdates.push_back(eventUpdate);
90275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9028b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
9029cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdResetEvent(commandBuffer, event, stageMask);
90305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
90315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
90329f8b71691386b3300f7de68034637b5cbbe4f84bAlex Smithstatic bool TransitionImageAspectLayout(layer_data *dev_data, GLOBAL_CB_NODE *pCB, const VkImageMemoryBarrier *mem_barrier,
9033bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        uint32_t level, uint32_t layer, VkImageAspectFlags aspect) {
90349f8b71691386b3300f7de68034637b5cbbe4f84bAlex Smith    if (!(mem_barrier->subresourceRange.aspectMask & aspect)) {
90359f8b71691386b3300f7de68034637b5cbbe4f84bAlex Smith        return false;
90369f8b71691386b3300f7de68034637b5cbbe4f84bAlex Smith    }
90379f8b71691386b3300f7de68034637b5cbbe4f84bAlex Smith    VkImageSubresource sub = {aspect, level, layer};
90389f8b71691386b3300f7de68034637b5cbbe4f84bAlex Smith    IMAGE_CMD_BUF_LAYOUT_NODE node;
90399f8b71691386b3300f7de68034637b5cbbe4f84bAlex Smith    if (!FindLayout(pCB, mem_barrier->image, sub, node)) {
9040bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        SetLayout(pCB, mem_barrier->image, sub, IMAGE_CMD_BUF_LAYOUT_NODE(mem_barrier->oldLayout, mem_barrier->newLayout));
90419f8b71691386b3300f7de68034637b5cbbe4f84bAlex Smith        return false;
90429f8b71691386b3300f7de68034637b5cbbe4f84bAlex Smith    }
90439f8b71691386b3300f7de68034637b5cbbe4f84bAlex Smith    bool skip = false;
90449f8b71691386b3300f7de68034637b5cbbe4f84bAlex Smith    if (mem_barrier->oldLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
90459f8b71691386b3300f7de68034637b5cbbe4f84bAlex Smith        // TODO: Set memory invalid which is in mem_tracker currently
90469f8b71691386b3300f7de68034637b5cbbe4f84bAlex Smith    } else if (node.layout != mem_barrier->oldLayout) {
9047bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9048bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
9049bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        "You cannot transition the layout of aspect %d from %s when current layout is %s.", aspect,
9050bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        string_VkImageLayout(mem_barrier->oldLayout), string_VkImageLayout(node.layout));
90519f8b71691386b3300f7de68034637b5cbbe4f84bAlex Smith    }
90529f8b71691386b3300f7de68034637b5cbbe4f84bAlex Smith    SetLayout(pCB, mem_barrier->image, sub, mem_barrier->newLayout);
90539f8b71691386b3300f7de68034637b5cbbe4f84bAlex Smith    return skip;
90549f8b71691386b3300f7de68034637b5cbbe4f84bAlex Smith}
90559f8b71691386b3300f7de68034637b5cbbe4f84bAlex Smith
9056ccde29c12e76d93133ec01c8b297f83f99abb545Mark Lobodzinski// TODO: Separate validation and layout state updates
9057e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool TransitionImageLayouts(VkCommandBuffer cmdBuffer, uint32_t memBarrierCount,
9058e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                                   const VkImageMemoryBarrier *pImgMemBarriers) {
90595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map);
90605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer);
9061e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip = false;
90625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t levelCount = 0;
90635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t layerCount = 0;
90645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
90655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < memBarrierCount; ++i) {
90665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto mem_barrier = &pImgMemBarriers[i];
9067cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!mem_barrier) continue;
90685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // TODO: Do not iterate over every possibility - consolidate where
90695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // possible
90705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        ResolveRemainingLevelsLayers(dev_data, &levelCount, &layerCount, mem_barrier->subresourceRange, mem_barrier->image);
90715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
90725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < levelCount; j++) {
90735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t level = mem_barrier->subresourceRange.baseMipLevel + j;
90745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            for (uint32_t k = 0; k < layerCount; k++) {
90755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                uint32_t layer = mem_barrier->subresourceRange.baseArrayLayer + k;
90769f8b71691386b3300f7de68034637b5cbbe4f84bAlex Smith                skip |= TransitionImageAspectLayout(dev_data, pCB, mem_barrier, level, layer, VK_IMAGE_ASPECT_COLOR_BIT);
90779f8b71691386b3300f7de68034637b5cbbe4f84bAlex Smith                skip |= TransitionImageAspectLayout(dev_data, pCB, mem_barrier, level, layer, VK_IMAGE_ASPECT_DEPTH_BIT);
90789f8b71691386b3300f7de68034637b5cbbe4f84bAlex Smith                skip |= TransitionImageAspectLayout(dev_data, pCB, mem_barrier, level, layer, VK_IMAGE_ASPECT_STENCIL_BIT);
90799f8b71691386b3300f7de68034637b5cbbe4f84bAlex Smith                skip |= TransitionImageAspectLayout(dev_data, pCB, mem_barrier, level, layer, VK_IMAGE_ASPECT_METADATA_BIT);
90805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
90815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
90825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
90835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip;
90845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
90855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
90865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Print readable FlagBits in FlagMask
9087e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic std::string string_VkAccessFlags(VkAccessFlags accessMask) {
90885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::string result;
90895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::string separator;
90905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
90915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (accessMask == 0) {
90925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        result = "[None]";
90935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
90945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        result = "[";
90955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto i = 0; i < 32; i++) {
90965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (accessMask & (1 << i)) {
90975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                result = result + separator + string_VkAccessFlagBits((VkAccessFlagBits)(1 << i));
90985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                separator = " | ";
90995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
91005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
91015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        result = result + "]";
91025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
91035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
91045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
91055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
91065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// AccessFlags MUST have 'required_bit' set, and may have one or more of 'optional_bits' set.
91075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// If required_bit is zero, accessMask must have at least one of 'optional_bits' set
91085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// TODO: Add tracking to ensure that at least one barrier has been set for these layout transitions
9109e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool ValidateMaskBits(const layer_data *my_data, VkCommandBuffer cmdBuffer, const VkAccessFlags &accessMask,
9110e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                             const VkImageLayout &layout, VkAccessFlags required_bit, VkAccessFlags optional_bits,
9111e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                             const char *type) {
9112e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
91135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
91145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if ((accessMask & required_bit) || (!required_bit && (accessMask & optional_bits))) {
911543986b69242d252623f4ee7278f1ecd07370adc8Chris Forbes        if (accessMask & ~(required_bit | optional_bits)) {
91165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // TODO: Verify against Valid Use
9117bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9118bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 DRAWSTATE_INVALID_BARRIER, "DS",
9119bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 "Additional bits in %s accessMask 0x%X %s are specified when layout is %s.", type, accessMask,
9120bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 string_VkAccessFlags(accessMask).c_str(), string_VkImageLayout(layout));
91215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
91225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
91235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!required_bit) {
91246044e94c13064f4663b31854951b7d4edf7877b2Michael Lentine            skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9125cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 DRAWSTATE_INVALID_BARRIER, "DS",
9126cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "%s AccessMask %d %s must contain at least one of access bits %d "
9127cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "%s when layout is %s, unless the app has previously added a "
9128cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "barrier for this transition.",
91295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                 type, accessMask, string_VkAccessFlags(accessMask).c_str(), optional_bits,
91305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                 string_VkAccessFlags(optional_bits).c_str(), string_VkImageLayout(layout));
91315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
91325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            std::string opt_bits;
91335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (optional_bits != 0) {
91345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                std::stringstream ss;
91355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                ss << optional_bits;
91365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                opt_bits = "and may have optional bits " + ss.str() + ' ' + string_VkAccessFlags(optional_bits);
91375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
91386044e94c13064f4663b31854951b7d4edf7877b2Michael Lentine            skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9139cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 DRAWSTATE_INVALID_BARRIER, "DS",
9140cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "%s AccessMask %d %s must have required access bit %d %s %s when "
9141cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "layout is %s, unless the app has previously added a barrier for "
9142cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "this transition.",
91435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                 type, accessMask, string_VkAccessFlags(accessMask).c_str(), required_bit,
91445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                 string_VkAccessFlags(required_bit).c_str(), opt_bits.c_str(), string_VkImageLayout(layout));
91455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
91465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
91475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
91485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
91495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9150e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool ValidateMaskBitsFromLayouts(const layer_data *my_data, VkCommandBuffer cmdBuffer, const VkAccessFlags &accessMask,
9151e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                                        const VkImageLayout &layout, const char *type) {
9152e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
91535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (layout) {
9154cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: {
9155cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
9156cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                          VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, type);
9157cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
91585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
9159cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: {
9160cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
9161cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                          VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, type);
9162cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
9163cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
9164cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: {
9165cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, VK_ACCESS_TRANSFER_WRITE_BIT, 0, type);
9166cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
9167cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
9168cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: {
9169cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            skip_call |= ValidateMaskBits(
9170cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                my_data, cmdBuffer, accessMask, layout, 0,
9171cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,
9172cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                type);
9173cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
9174cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
9175cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: {
9176cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, 0,
9177cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                          VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT, type);
9178cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
9179cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
9180cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: {
9181cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, VK_ACCESS_TRANSFER_READ_BIT, 0, type);
9182cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
9183cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
9184cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: {
9185cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, VK_ACCESS_MEMORY_READ_BIT, 0, type);
9186cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
9187cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
9188cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_IMAGE_LAYOUT_UNDEFINED: {
9189cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (accessMask != 0) {
9190cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // TODO: Verify against Valid Use section spec
9191cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
9192cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     __LINE__, DRAWSTATE_INVALID_BARRIER, "DS",
9193cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "Additional bits in %s accessMask 0x%X %s are specified when layout is %s.", type, accessMask,
9194cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     string_VkAccessFlags(accessMask).c_str(), string_VkImageLayout(layout));
9195cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
9196cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
9197cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
9198cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_IMAGE_LAYOUT_GENERAL:
9199cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default: { break; }
92005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
92015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
92025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
92035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9204e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool ValidateBarriers(const char *funcName, VkCommandBuffer cmdBuffer, uint32_t memBarrierCount,
9205e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                             const VkMemoryBarrier *pMemBarriers, uint32_t bufferBarrierCount,
9206e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                             const VkBufferMemoryBarrier *pBufferMemBarriers, uint32_t imageMemBarrierCount,
9207e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                             const VkImageMemoryBarrier *pImageMemBarriers) {
9208a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis    bool skip = false;
92095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map);
92105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer);
92115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB->activeRenderPass && memBarrierCount) {
9212ee691f5c5fa87aac3750454d2bca2cb582e4e817Chris Forbes        if (!pCB->activeRenderPass->hasSelfDependency[pCB->activeSubpass]) {
9213a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9214cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            DRAWSTATE_INVALID_BARRIER, "DS",
9215cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s: Barriers cannot be set during subpass %d "
9216cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "with no self dependency specified.",
9217a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            funcName, pCB->activeSubpass);
92185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
92195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
92205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < imageMemBarrierCount; ++i) {
92215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto mem_barrier = &pImageMemBarriers[i];
92221facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        auto image_data = getImageState(dev_data, mem_barrier->image);
92236d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis        if (image_data) {
92245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t src_q_f_index = mem_barrier->srcQueueFamilyIndex;
92255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t dst_q_f_index = mem_barrier->dstQueueFamilyIndex;
92266d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            if (image_data->createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) {
92275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // srcQueueFamilyIndex and dstQueueFamilyIndex must both
92285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // be VK_QUEUE_FAMILY_IGNORED
92295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if ((src_q_f_index != VK_QUEUE_FAMILY_IGNORED) || (dst_q_f_index != VK_QUEUE_FAMILY_IGNORED)) {
9230cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip |=
9231cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9232cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                DRAWSTATE_INVALID_QUEUE_INDEX, "DS", "%s: Image Barrier for image 0x%" PRIx64
9233cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                                     " was created with sharingMode of "
9234cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                                     "VK_SHARING_MODE_CONCURRENT. Src and dst "
9235cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                                     "queueFamilyIndices must be VK_QUEUE_FAMILY_IGNORED.",
9236cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                funcName, reinterpret_cast<const uint64_t &>(mem_barrier->image));
92375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
92385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else {
92395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // Sharing mode is VK_SHARING_MODE_EXCLUSIVE. srcQueueFamilyIndex and
92405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // dstQueueFamilyIndex must either both be VK_QUEUE_FAMILY_IGNORED,
92415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // or both be a valid queue family
92425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (((src_q_f_index == VK_QUEUE_FAMILY_IGNORED) || (dst_q_f_index == VK_QUEUE_FAMILY_IGNORED)) &&
92435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    (src_q_f_index != dst_q_f_index)) {
9244a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                    skip |=
92455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9246cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                DRAWSTATE_INVALID_QUEUE_INDEX, "DS", "%s: Image 0x%" PRIx64
9247cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                                     " was created with sharingMode "
92485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                                     "of VK_SHARING_MODE_EXCLUSIVE. If one of src- or "
92495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                                     "dstQueueFamilyIndex is VK_QUEUE_FAMILY_IGNORED, both "
92505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                                     "must be.",
92515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                funcName, reinterpret_cast<const uint64_t &>(mem_barrier->image));
92525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                } else if (((src_q_f_index != VK_QUEUE_FAMILY_IGNORED) && (dst_q_f_index != VK_QUEUE_FAMILY_IGNORED)) &&
9253b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis                           ((src_q_f_index >= dev_data->phys_dev_properties.queue_family_properties.size()) ||
9254b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis                            (dst_q_f_index >= dev_data->phys_dev_properties.queue_family_properties.size()))) {
9255a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
9256a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                    __LINE__, DRAWSTATE_INVALID_QUEUE_INDEX, "DS",
9257cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    "%s: Image 0x%" PRIx64
9258cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    " was created with sharingMode "
9259a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                    "of VK_SHARING_MODE_EXCLUSIVE, but srcQueueFamilyIndex %d"
9260a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                    " or dstQueueFamilyIndex %d is greater than " PRINTF_SIZE_T_SPECIFIER
9261a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                    "queueFamilies crated for this device.",
9262a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                    funcName, reinterpret_cast<const uint64_t &>(mem_barrier->image), src_q_f_index, dst_q_f_index,
9263a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                    dev_data->phys_dev_properties.queue_family_properties.size());
92645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
92655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
92665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
92675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
92685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (mem_barrier) {
9269d678ec4f57d80aa89c24562e9ffe941d8d69e455Tony Barbour            if (mem_barrier->oldLayout != mem_barrier->newLayout) {
9270a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                skip |=
9271d678ec4f57d80aa89c24562e9ffe941d8d69e455Tony Barbour                    ValidateMaskBitsFromLayouts(dev_data, cmdBuffer, mem_barrier->srcAccessMask, mem_barrier->oldLayout, "Source");
9272a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                skip |=
9273d678ec4f57d80aa89c24562e9ffe941d8d69e455Tony Barbour                    ValidateMaskBitsFromLayouts(dev_data, cmdBuffer, mem_barrier->dstAccessMask, mem_barrier->newLayout, "Dest");
9274d678ec4f57d80aa89c24562e9ffe941d8d69e455Tony Barbour            }
92755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (mem_barrier->newLayout == VK_IMAGE_LAYOUT_UNDEFINED || mem_barrier->newLayout == VK_IMAGE_LAYOUT_PREINITIALIZED) {
9276a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9277cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                DRAWSTATE_INVALID_BARRIER, "DS",
9278cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                "%s: Image Layout cannot be transitioned to UNDEFINED or "
9279cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                "PREINITIALIZED.",
9280a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                funcName);
92815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
92821d5109d5e0dcc530b27e632e73e1be5e12a28dcdJamie Madill            VkFormat format = VK_FORMAT_UNDEFINED;
92831d5109d5e0dcc530b27e632e73e1be5e12a28dcdJamie Madill            uint32_t arrayLayers = 0, mipLevels = 0;
92845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            bool imageFound = false;
92856d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            if (image_data) {
92866d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis                format = image_data->createInfo.format;
92876d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis                arrayLayers = image_data->createInfo.arrayLayers;
92886d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis                mipLevels = image_data->createInfo.mipLevels;
92895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                imageFound = true;
92905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else if (dev_data->device_extensions.wsi_enabled) {
9291170dc65b45f6bcdec47e02b3aa19435e55b32804Tobin Ehlis                auto imageswap_data = getSwapchainFromImage(dev_data, mem_barrier->image);
9292170dc65b45f6bcdec47e02b3aa19435e55b32804Tobin Ehlis                if (imageswap_data) {
9293b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis                    auto swapchain_data = getSwapchainNode(dev_data, imageswap_data);
9294b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis                    if (swapchain_data) {
9295b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis                        format = swapchain_data->createInfo.imageFormat;
9296b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis                        arrayLayers = swapchain_data->createInfo.imageArrayLayers;
92975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        mipLevels = 1;
92985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        imageFound = true;
92995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
93005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
93015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
93025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (imageFound) {
9303364a03b109f0b2b37be2e13d293fa93b8af5203aMike Weiblen                skip |= ValidateImageSubrangeLevelLayerCounts(dev_data, mem_barrier->subresourceRange, funcName,
9304364a03b109f0b2b37be2e13d293fa93b8af5203aMike Weiblen                                                              VALIDATION_ERROR_00768, VALIDATION_ERROR_00769);
9305c37c65e9ff3a0abc86e706ee61d21e1dec882731Tobin Ehlis                auto aspect_mask = mem_barrier->subresourceRange.aspectMask;
9306a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                skip |= ValidateImageAspectMask(dev_data, image_data->image, format, aspect_mask, funcName);
9307f0d091deca3d4b90e1f31d75e062684dca160ad1Michael Lentine                int layerCount = (mem_barrier->subresourceRange.layerCount == VK_REMAINING_ARRAY_LAYERS)
9308f0d091deca3d4b90e1f31d75e062684dca160ad1Michael Lentine                                     ? 1
9309f0d091deca3d4b90e1f31d75e062684dca160ad1Michael Lentine                                     : mem_barrier->subresourceRange.layerCount;
9310f0d091deca3d4b90e1f31d75e062684dca160ad1Michael Lentine                if ((mem_barrier->subresourceRange.baseArrayLayer + layerCount) > arrayLayers) {
9311a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
9312cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    __LINE__, DRAWSTATE_INVALID_BARRIER, "DS",
9313cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    "%s: Subresource must have the sum of the "
9314cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    "baseArrayLayer (%d) and layerCount (%d) be less "
9315cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    "than or equal to the total number of layers (%d).",
9316a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                    funcName, mem_barrier->subresourceRange.baseArrayLayer,
9317a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                    mem_barrier->subresourceRange.layerCount, arrayLayers);
93185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
9319f0d091deca3d4b90e1f31d75e062684dca160ad1Michael Lentine                int levelCount = (mem_barrier->subresourceRange.levelCount == VK_REMAINING_MIP_LEVELS)
9320f0d091deca3d4b90e1f31d75e062684dca160ad1Michael Lentine                                     ? 1
9321f0d091deca3d4b90e1f31d75e062684dca160ad1Michael Lentine                                     : mem_barrier->subresourceRange.levelCount;
9322f0d091deca3d4b90e1f31d75e062684dca160ad1Michael Lentine                if ((mem_barrier->subresourceRange.baseMipLevel + levelCount) > mipLevels) {
9323cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
9324cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    __LINE__, DRAWSTATE_INVALID_BARRIER, "DS",
9325cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    "%s: Subresource must have the sum of the baseMipLevel "
9326cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    "(%d) and levelCount (%d) be less than or equal to "
9327cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    "the total number of levels (%d).",
9328cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    funcName, mem_barrier->subresourceRange.baseMipLevel, mem_barrier->subresourceRange.levelCount,
9329cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    mipLevels);
93305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
93315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
93325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
93335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
93345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < bufferBarrierCount; ++i) {
93355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto mem_barrier = &pBufferMemBarriers[i];
93365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (pCB->activeRenderPass) {
9337a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9338a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            DRAWSTATE_INVALID_BARRIER, "DS", "%s: Buffer Barriers cannot be used during a render pass.", funcName);
93395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
9340cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!mem_barrier) continue;
93415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
93425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Validate buffer barrier queue family indices
93435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if ((mem_barrier->srcQueueFamilyIndex != VK_QUEUE_FAMILY_IGNORED &&
9344b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis             mem_barrier->srcQueueFamilyIndex >= dev_data->phys_dev_properties.queue_family_properties.size()) ||
93455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            (mem_barrier->dstQueueFamilyIndex != VK_QUEUE_FAMILY_IGNORED &&
9346b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis             mem_barrier->dstQueueFamilyIndex >= dev_data->phys_dev_properties.queue_family_properties.size())) {
9347a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9348a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            DRAWSTATE_INVALID_QUEUE_INDEX, "DS",
9349cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s: Buffer Barrier 0x%" PRIx64
9350cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            " has QueueFamilyIndex greater "
9351a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            "than the number of QueueFamilies (" PRINTF_SIZE_T_SPECIFIER ") for this device.",
9352a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            funcName, reinterpret_cast<const uint64_t &>(mem_barrier->buffer),
9353a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            dev_data->phys_dev_properties.queue_family_properties.size());
93545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
93555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
93565cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        auto buffer_state = getBufferState(dev_data, mem_barrier->buffer);
93575cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        if (buffer_state) {
93585cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            auto buffer_size = buffer_state->requirements.size;
93595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (mem_barrier->offset >= buffer_size) {
9360a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9361a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                DRAWSTATE_INVALID_BARRIER, "DS", "%s: Buffer Barrier 0x%" PRIx64 " has offset 0x%" PRIx64
9362a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                                                 " which is not less than total size 0x%" PRIx64 ".",
9363a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                funcName, reinterpret_cast<const uint64_t &>(mem_barrier->buffer),
9364a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                reinterpret_cast<const uint64_t &>(mem_barrier->offset),
9365a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                reinterpret_cast<const uint64_t &>(buffer_size));
93665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else if (mem_barrier->size != VK_WHOLE_SIZE && (mem_barrier->offset + mem_barrier->size > buffer_size)) {
9367a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                skip |= log_msg(
936894c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9369414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                    DRAWSTATE_INVALID_BARRIER, "DS", "%s: Buffer Barrier 0x%" PRIx64 " has offset 0x%" PRIx64 " and size 0x%" PRIx64
9370414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                                                     " whose sum is greater than total size 0x%" PRIx64 ".",
937194c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis                    funcName, reinterpret_cast<const uint64_t &>(mem_barrier->buffer),
937294c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis                    reinterpret_cast<const uint64_t &>(mem_barrier->offset), reinterpret_cast<const uint64_t &>(mem_barrier->size),
937394c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis                    reinterpret_cast<const uint64_t &>(buffer_size));
93745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
93755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
93765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9377a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis    return skip;
93785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
93795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9380bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskibool validateEventStageMask(VkQueue queue, GLOBAL_CB_NODE *pCB, uint32_t eventCount, size_t firstEventIndex,
9381bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            VkPipelineStageFlags sourceStageMask) {
9382b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    bool skip_call = false;
9383b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    VkPipelineStageFlags stageMask = 0;
9384b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map);
9385b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    for (uint32_t i = 0; i < eventCount; ++i) {
93862ab14387df9b890fe4b13494ea249dd03cf898d2Chris Forbes        auto event = pCB->events[firstEventIndex + i];
9387b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        auto queue_data = dev_data->queueMap.find(queue);
9388cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (queue_data == dev_data->queueMap.end()) return false;
93892ab14387df9b890fe4b13494ea249dd03cf898d2Chris Forbes        auto event_data = queue_data->second.eventToStageMap.find(event);
9390b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        if (event_data != queue_data->second.eventToStageMap.end()) {
9391b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            stageMask |= event_data->second;
9392b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        } else {
93939556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis            auto global_event_data = getEventNode(dev_data, event);
93949556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis            if (!global_event_data) {
9395b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT,
939627c3e0dda9e30d1d334728bbd373e8d7011257d4Chris Forbes                                     reinterpret_cast<const uint64_t &>(event), __LINE__, DRAWSTATE_INVALID_EVENT, "DS",
939727c3e0dda9e30d1d334728bbd373e8d7011257d4Chris Forbes                                     "Event 0x%" PRIx64 " cannot be waited on if it has never been set.",
93982ab14387df9b890fe4b13494ea249dd03cf898d2Chris Forbes                                     reinterpret_cast<const uint64_t &>(event));
9399b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            } else {
94009556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis                stageMask |= global_event_data->stageMask;
9401b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            }
9402b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        }
9403b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
9404c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    // TODO: Need to validate that host_bit is only set if set event is called
9405c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    // but set event can be called at any time.
9406c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    if (sourceStageMask != stageMask && sourceStageMask != (stageMask | VK_PIPELINE_STAGE_HOST_BIT)) {
9407c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9408cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             VALIDATION_ERROR_00254, "DS",
9409cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "Submitting cmdbuffer with call to VkCmdWaitEvents "
9410cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "using srcStageMask 0x%X which must be the bitwise "
9411cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "OR of the stageMask parameters used in calls to "
9412cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "vkCmdSetEvent and VK_PIPELINE_STAGE_HOST_BIT if "
9413cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "used with vkSetEvent but instead is 0x%X. %s",
94149bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             sourceStageMask, stageMask, validation_error_map[VALIDATION_ERROR_00254]);
9415b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
9416b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    return skip_call;
9417b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine}
9418b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine
941907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski// Note that we only check bits that HAVE required queueflags -- don't care entries are skipped
942007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinskistatic std::unordered_map<VkPipelineStageFlags, VkQueueFlags> supported_pipeline_stages_table = {
942107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT},
942207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT},
942307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_QUEUE_GRAPHICS_BIT},
942407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
942507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
942607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
942707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
942807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
942907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, VK_QUEUE_GRAPHICS_BIT},
943007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_QUEUE_GRAPHICS_BIT},
943107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_QUEUE_GRAPHICS_BIT},
943207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_QUEUE_COMPUTE_BIT},
943307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_TRANSFER_BIT, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT},
943407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_QUEUE_GRAPHICS_BIT}};
943507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
943607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinskistatic const VkPipelineStageFlags stage_flag_bit_array[] = {VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX,
943707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,
943807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
943907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
944007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT,
944107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT,
944207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT,
944307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
944407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
944507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
944607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
944707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
944807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_TRANSFER_BIT,
944907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT};
945007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
945107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinskibool CheckStageMaskQueueCompatibility(layer_data *dev_data, VkCommandBuffer command_buffer, VkPipelineStageFlags stage_mask,
945207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                      VkQueueFlags queue_flags, const char *function, const char *src_or_dest,
945307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                      UNIQUE_VALIDATION_ERROR_CODE error_code) {
945407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    bool skip = false;
945507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    // Lookup each bit in the stagemask and check for overlap between its table bits and queue_flags
945607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    for (const auto &item : stage_flag_bit_array) {
945707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        if (stage_mask & item) {
945807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski            if ((supported_pipeline_stages_table[item] & queue_flags) == 0) {
945907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                skip |=
946007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
946107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            reinterpret_cast<uint64_t &>(command_buffer), __LINE__, error_code, "DL",
946207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            "%s(): %s flag %s is not compatible with the queue family properties of this "
946307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            "command buffer. %s",
946407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            function, src_or_dest, string_VkPipelineStageFlagBits(static_cast<VkPipelineStageFlagBits>(item)),
946507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            validation_error_map[error_code]);
946607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski            }
946707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        }
946807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    }
946907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    return skip;
947007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski}
947107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
947207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinskibool ValidateStageMasksAgainstQueueCapabilities(layer_data *dev_data, GLOBAL_CB_NODE *cb_state,
947307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                VkPipelineStageFlags source_stage_mask, VkPipelineStageFlags dest_stage_mask,
947407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                const char *function, UNIQUE_VALIDATION_ERROR_CODE error_code) {
947507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    bool skip = false;
947607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    uint32_t queue_family_index = dev_data->commandPoolMap[cb_state->createInfo.commandPool].queueFamilyIndex;
947707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    instance_layer_data *instance_data = get_my_data_ptr(get_dispatch_key(dev_data->physical_device), instance_layer_data_map);
947807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    auto physical_device_state = getPhysicalDeviceState(instance_data, dev_data->physical_device);
947907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
948007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    // Any pipeline stage included in srcStageMask or dstStageMask must be supported by the capabilities of the queue family
948107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    // specified by the queueFamilyIndex member of the VkCommandPoolCreateInfo structure that was used to create the VkCommandPool
948207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    // that commandBuffer was allocated from, as specified in the table of supported pipeline stages.
948307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
948407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    if (queue_family_index < physical_device_state->queue_family_properties.size()) {
948507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        VkQueueFlags specified_queue_flags = physical_device_state->queue_family_properties[queue_family_index].queueFlags;
948607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
948707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        if ((source_stage_mask & VK_PIPELINE_STAGE_ALL_COMMANDS_BIT) == 0) {
948807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski            skip |= CheckStageMaskQueueCompatibility(dev_data, cb_state->commandBuffer, source_stage_mask, specified_queue_flags,
948907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                     function, "srcStageMask", error_code);
949007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        }
949107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        if ((dest_stage_mask & VK_PIPELINE_STAGE_ALL_COMMANDS_BIT) == 0) {
949207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski            skip |= CheckStageMaskQueueCompatibility(dev_data, cb_state->commandBuffer, dest_stage_mask, specified_queue_flags,
949307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                     function, "dstStageMask", error_code);
949407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        }
949507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    }
949607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    return skip;
949707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski}
949807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
9499d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents,
9500d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                         VkPipelineStageFlags sourceStageMask, VkPipelineStageFlags dstStageMask,
9501d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                         uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
9502d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                         uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
9503d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                         uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
9504d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    bool skip = false;
95055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
9506b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
9507d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    GLOBAL_CB_NODE *cb_state = getCBNode(dev_data, commandBuffer);
9508d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    if (cb_state) {
9509d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        skip |= ValidateStageMasksAgainstQueueCapabilities(dev_data, cb_state, sourceStageMask, dstStageMask, "vkCmdWaitEvents",
9510d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                                           VALIDATION_ERROR_02510);
9511208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip |= ValidateStageMaskGsTsEnables(dev_data, sourceStageMask, "vkCmdWaitEvents()", VALIDATION_ERROR_02067,
9512208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                                             VALIDATION_ERROR_02069);
9513208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip |= ValidateStageMaskGsTsEnables(dev_data, dstStageMask, "vkCmdWaitEvents()", VALIDATION_ERROR_02068,
9514208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                                             VALIDATION_ERROR_02070);
9515d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        auto first_event_index = cb_state->events.size();
95165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < eventCount; ++i) {
95174710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis            auto event_state = getEventNode(dev_data, pEvents[i]);
95184710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis            if (event_state) {
95194710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis                addCommandBufferBinding(&event_state->cb_bindings,
9520ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis                                        {reinterpret_cast<const uint64_t &>(pEvents[i]), VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT},
9521d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                        cb_state);
9522d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                event_state->cb_bindings.insert(cb_state);
9523ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis            }
9524d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski            cb_state->waitedEvents.insert(pEvents[i]);
9525d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski            cb_state->events.push_back(pEvents[i]);
95265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
9527d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        std::function<bool(VkQueue)> event_update =
9528d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski            std::bind(validateEventStageMask, std::placeholders::_1, cb_state, eventCount, first_event_index, sourceStageMask);
9529d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        cb_state->eventUpdates.push_back(event_update);
9530d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        if (cb_state->state == CB_RECORDING) {
953129f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis            skip |= ValidateCmd(dev_data, cb_state, CMD_WAITEVENTS, "vkCmdWaitEvents()");
953229f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis            UpdateCmdBufferLastCmd(dev_data, cb_state, CMD_WAITEVENTS);
95335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
9534d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski            skip |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdWaitEvents()");
95355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
9536d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        skip |= TransitionImageLayouts(commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers);
9537364a03b109f0b2b37be2e13d293fa93b8af5203aMike Weiblen        skip |= ValidateBarriers("vkCmdWaitEvents()", commandBuffer, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
9538d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                 pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
95395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9540b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
9541d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    if (!skip)
95424a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdWaitEvents(commandBuffer, eventCount, pEvents, sourceStageMask, dstStageMask,
95434a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                               memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers,
95444a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                               imageMemoryBarrierCount, pImageMemoryBarriers);
95455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
95465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9547d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask,
9548d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                              VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags,
9549d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                              uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
9550d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                              uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
9551d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                              uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
9552d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    bool skip = false;
95535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
9554b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
9555d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    GLOBAL_CB_NODE *cb_state = getCBNode(dev_data, commandBuffer);
9556d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    if (cb_state) {
9557d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        skip |= ValidateStageMasksAgainstQueueCapabilities(dev_data, cb_state, srcStageMask, dstStageMask, "vkCmdPipelineBarrier",
9558d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                                           VALIDATION_ERROR_02513);
955929f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip |= ValidateCmd(dev_data, cb_state, CMD_PIPELINEBARRIER, "vkCmdPipelineBarrier()");
9560208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip |= ValidateStageMaskGsTsEnables(dev_data, srcStageMask, "vkCmdPipelineBarrier()", VALIDATION_ERROR_00265,
9561208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                                             VALIDATION_ERROR_00267);
9562208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip |= ValidateStageMaskGsTsEnables(dev_data, dstStageMask, "vkCmdPipelineBarrier()", VALIDATION_ERROR_00266,
9563208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                                             VALIDATION_ERROR_00268);
956429f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        UpdateCmdBufferLastCmd(dev_data, cb_state, CMD_PIPELINEBARRIER);
9565d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        skip |= TransitionImageLayouts(commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers);
9566364a03b109f0b2b37be2e13d293fa93b8af5203aMike Weiblen        skip |= ValidateBarriers("vkCmdPipelineBarrier()", commandBuffer, memoryBarrierCount, pMemoryBarriers,
9567d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                 bufferMemoryBarrierCount, pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
95685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9569b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
9570d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    if (!skip)
95714a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, dependencyFlags, memoryBarrierCount,
95724a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                    pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers,
95734a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                    imageMemoryBarrierCount, pImageMemoryBarriers);
95745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
95755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9576d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentinebool setQueryState(VkQueue queue, VkCommandBuffer commandBuffer, QueryObject object, bool value) {
9577d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
9578d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
9579d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    if (pCB) {
9580d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        pCB->queryToStateMap[object] = value;
9581d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    }
9582d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    auto queue_data = dev_data->queueMap.find(queue);
9583d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    if (queue_data != dev_data->queueMap.end()) {
9584d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        queue_data->second.queryToStateMap[object] = value;
9585d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    }
9586d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    return false;
9587d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine}
9588d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine
9589bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBeginQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot, VkFlags flags) {
959083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
95915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
9592b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
95935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
95945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
95955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        QueryObject query = {queryPool, slot};
95965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->activeQueries.insert(query);
95975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!pCB->startedQueries.count(query)) {
95985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pCB->startedQueries.insert(query);
95995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
960029f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_BEGINQUERY, "vkCmdBeginQuery()");
960129f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        UpdateCmdBufferLastCmd(dev_data, pCB, CMD_BEGINQUERY);
9602ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis        addCommandBufferBinding(&getQueryPoolNode(dev_data, queryPool)->cb_bindings,
9603ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis                                {reinterpret_cast<uint64_t &>(queryPool), VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT}, pCB);
96045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9605b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
9606cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdBeginQuery(commandBuffer, queryPool, slot, flags);
96075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
96085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
960989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdEndQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot) {
961083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
96115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
9612b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
96135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
96145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
96155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        QueryObject query = {queryPool, slot};
96165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!pCB->activeQueries.count(query)) {
961783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |=
96185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
96199bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        VALIDATION_ERROR_01041, "DS", "Ending a query before it was started: queryPool 0x%" PRIx64 ", index %d. %s",
96209bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        (uint64_t)(queryPool), slot, validation_error_map[VALIDATION_ERROR_01041]);
96215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
96225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pCB->activeQueries.erase(query);
96235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
9624c2ec509029604290e981885108c06a9b7de565c1Karl Schultz        std::function<bool(VkQueue)> queryUpdate = std::bind(setQueryState, std::placeholders::_1, commandBuffer, query, true);
9625d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        pCB->queryUpdates.push_back(queryUpdate);
96265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (pCB->state == CB_RECORDING) {
962729f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis            skip_call |= ValidateCmd(dev_data, pCB, CMD_ENDQUERY, "VkCmdEndQuery()");
962829f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis            UpdateCmdBufferLastCmd(dev_data, pCB, CMD_ENDQUERY);
96295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
963083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdEndQuery()");
96315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
9632ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis        addCommandBufferBinding(&getQueryPoolNode(dev_data, queryPool)->cb_bindings,
9633ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis                                {reinterpret_cast<uint64_t &>(queryPool), VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT}, pCB);
96345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9635b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
9636cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdEndQuery(commandBuffer, queryPool, slot);
96375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
96385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9639bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdResetQueryPool(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery,
9640bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                             uint32_t queryCount) {
964183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
96425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
9643b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
96445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
96455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
96465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < queryCount; i++) {
96475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            QueryObject query = {queryPool, firstQuery + i};
96485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pCB->waitedEventsBeforeQueryReset[query] = pCB->waitedEvents;
9649c2ec509029604290e981885108c06a9b7de565c1Karl Schultz            std::function<bool(VkQueue)> queryUpdate = std::bind(setQueryState, std::placeholders::_1, commandBuffer, query, false);
9650d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            pCB->queryUpdates.push_back(queryUpdate);
96515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
96525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (pCB->state == CB_RECORDING) {
965329f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis            skip_call |= ValidateCmd(dev_data, pCB, CMD_RESETQUERYPOOL, "VkCmdResetQueryPool()");
965429f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis            UpdateCmdBufferLastCmd(dev_data, pCB, CMD_RESETQUERYPOOL);
96555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
965683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdResetQueryPool()");
96575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
9658ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen        skip_call |= insideRenderPass(dev_data, pCB, "vkCmdResetQueryPool()", VALIDATION_ERROR_01025);
9659ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis        addCommandBufferBinding(&getQueryPoolNode(dev_data, queryPool)->cb_bindings,
9660ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis                                {reinterpret_cast<uint64_t &>(queryPool), VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT}, pCB);
96615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9662b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
9663cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdResetQueryPool(commandBuffer, queryPool, firstQuery, queryCount);
96645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
96655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9666d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentinebool validateQuery(VkQueue queue, GLOBAL_CB_NODE *pCB, VkQueryPool queryPool, uint32_t queryCount, uint32_t firstQuery) {
9667d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    bool skip_call = false;
9668d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(pCB->commandBuffer), layer_data_map);
9669d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    auto queue_data = dev_data->queueMap.find(queue);
9670cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (queue_data == dev_data->queueMap.end()) return false;
9671d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    for (uint32_t i = 0; i < queryCount; i++) {
9672d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        QueryObject query = {queryPool, firstQuery + i};
9673d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        auto query_data = queue_data->second.queryToStateMap.find(query);
9674d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        bool fail = false;
9675d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        if (query_data != queue_data->second.queryToStateMap.end()) {
9676d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            if (!query_data->second) {
9677d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                fail = true;
9678d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            }
9679d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        } else {
9680d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            auto global_query_data = dev_data->queryToStateMap.find(query);
9681d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            if (global_query_data != dev_data->queryToStateMap.end()) {
9682d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                if (!global_query_data->second) {
9683d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                    fail = true;
9684d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                }
9685d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            } else {
9686d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                fail = true;
9687d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            }
9688d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        }
9689d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        if (fail) {
9690d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9691d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                                 DRAWSTATE_INVALID_QUERY, "DS",
9692d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                                 "Requesting a copy from query to buffer with invalid query: queryPool 0x%" PRIx64 ", index %d",
9693d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                                 reinterpret_cast<uint64_t &>(queryPool), firstQuery + i);
9694d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        }
9695d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    }
9696d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    return skip_call;
9697d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine}
9698d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine
9699bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdCopyQueryPoolResults(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery,
9700bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset,
9701bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   VkDeviceSize stride, VkQueryResultFlags flags) {
970283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
97035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
9704b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
9705ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
97069f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis    auto cb_node = getCBNode(dev_data, commandBuffer);
97075cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    auto dst_buff_state = getBufferState(dev_data, dstBuffer);
97085cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (cb_node && dst_buff_state) {
970935ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis        skip_call |= ValidateMemoryIsBoundToBuffer(dev_data, dst_buff_state, "vkCmdCopyQueryPoolResults()", VALIDATION_ERROR_02526);
9710ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Update bindings between buffer and cmd buffer
97115cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        AddCommandBufferBindingBuffer(dev_data, cb_node, dst_buff_state);
9712ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Validate that DST buffer has correct usage flags set
97131b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes        skip_call |=
97145cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            ValidateBufferUsageFlags(dev_data, dst_buff_state, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, VALIDATION_ERROR_01066,
97151b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes                                     "vkCmdCopyQueryPoolResults()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
9716e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
97175cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            SetBufferMemoryValid(dev_data, dst_buff_state, true);
9718e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
97195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        };
97209f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
9721d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        std::function<bool(VkQueue)> queryUpdate =
9722ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis            std::bind(validateQuery, std::placeholders::_1, cb_node, queryPool, queryCount, firstQuery);
9723ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        cb_node->queryUpdates.push_back(queryUpdate);
9724ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        if (cb_node->state == CB_RECORDING) {
972529f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis            skip_call |= ValidateCmd(dev_data, cb_node, CMD_COPYQUERYPOOLRESULTS, "vkCmdCopyQueryPoolResults()");
972629f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis            UpdateCmdBufferLastCmd(dev_data, cb_node, CMD_COPYQUERYPOOLRESULTS);
97275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
972883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdCopyQueryPoolResults()");
97295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
9730ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen        skip_call |= insideRenderPass(dev_data, cb_node, "vkCmdCopyQueryPoolResults()", VALIDATION_ERROR_01074);
9731ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis        addCommandBufferBinding(&getQueryPoolNode(dev_data, queryPool)->cb_bindings,
9732ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis                                {reinterpret_cast<uint64_t &>(queryPool), VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT}, cb_node);
9733ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
9734ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
97355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9736b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
973783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (!skip_call)
97384a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdCopyQueryPoolResults(commandBuffer, queryPool, firstQuery, queryCount, dstBuffer, dstOffset,
97394a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                         stride, flags);
97405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
97415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9742bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdPushConstants(VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags,
9743bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                            uint32_t offset, uint32_t size, const void *pValues) {
974483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
97455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
9746b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
97475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
97485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
97495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (pCB->state == CB_RECORDING) {
975029f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis            skip_call |= ValidateCmd(dev_data, pCB, CMD_PUSHCONSTANTS, "vkCmdPushConstants()");
975129f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis            UpdateCmdBufferLastCmd(dev_data, pCB, CMD_PUSHCONSTANTS);
97525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
975383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdPushConstants()");
97545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
97555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
975683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    skip_call |= validatePushConstantRange(dev_data, offset, size, "vkCmdPushConstants()");
97579e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    if (0 == stageFlags) {
975883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
97599bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             VALIDATION_ERROR_00996, "DS", "vkCmdPushConstants() call has no stageFlags set. %s",
97609bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             validation_error_map[VALIDATION_ERROR_00996]);
97619e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    }
97629e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz
9763a95cb74c9d0947ab3821b15e1289755286ea78eeKarl Schultz    // Check if push constant update is within any of the ranges with the same stage flags specified in pipeline layout.
9764c2a5a36d03bbe52f5854a5884346e4a84115e259Tobin Ehlis    auto pipeline_layout = getPipelineLayout(dev_data, layout);
976515a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis    // Coalesce adjacent/overlapping pipeline ranges before checking to see if incoming range is
976615a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis    // contained in the pipeline ranges.
976715a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis    // Build a {start, end} span list for ranges with matching stage flags.
976815a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis    const auto &ranges = pipeline_layout->push_constant_ranges;
976915a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis    struct span {
977015a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        uint32_t start;
977115a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        uint32_t end;
977215a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis    };
977315a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis    std::vector<span> spans;
977415a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis    spans.reserve(ranges.size());
977515a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis    for (const auto &iter : ranges) {
977615a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        if (iter.stageFlags == stageFlags) {
977715a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis            spans.push_back({iter.offset, iter.offset + iter.size});
977815a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        }
977915a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis    }
978015a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis    if (spans.size() == 0) {
978115a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        // There were no ranges that matched the stageFlags.
978215a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        skip_call |=
978315a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9784cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    VALIDATION_ERROR_00988, "DS", "vkCmdPushConstants() stageFlags = 0x%" PRIx32
9785cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                  " do not match "
97869bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                                  "the stageFlags in any of the ranges in pipeline layout 0x%" PRIx64 ". %s",
97879bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                    (uint32_t)stageFlags, (uint64_t)layout, validation_error_map[VALIDATION_ERROR_00988]);
97889e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    } else {
978915a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        // Sort span list by start value.
979015a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        struct comparer {
979115a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis            bool operator()(struct span i, struct span j) { return i.start < j.start; }
979215a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        } my_comparer;
979315a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        std::sort(spans.begin(), spans.end(), my_comparer);
979415a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis
979515a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        // Examine two spans at a time.
979615a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        std::vector<span>::iterator current = spans.begin();
979715a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        std::vector<span>::iterator next = current + 1;
979815a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        while (next != spans.end()) {
979915a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis            if (current->end < next->start) {
980015a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                // There is a gap; cannot coalesce. Move to the next two spans.
980115a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                ++current;
980215a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                ++next;
980315a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis            } else {
980415a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                // Coalesce the two spans.  The start of the next span
980515a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                // is within the current span, so pick the larger of
980615a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                // the end values to extend the current span.
980715a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                // Then delete the next span and set next to the span after it.
980815a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                current->end = max(current->end, next->end);
980915a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                next = spans.erase(next);
98109e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz            }
98119e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
9812a95cb74c9d0947ab3821b15e1289755286ea78eeKarl Schultz
981315a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        // Now we can check if the incoming range is within any of the spans.
981415a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        bool contained_in_a_range = false;
981515a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        for (uint32_t i = 0; i < spans.size(); ++i) {
981615a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis            if ((offset >= spans[i].start) && ((uint64_t)offset + (uint64_t)size <= (uint64_t)spans[i].end)) {
981715a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                contained_in_a_range = true;
981815a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                break;
9819a95cb74c9d0947ab3821b15e1289755286ea78eeKarl Schultz            }
98209e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
982115a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        if (!contained_in_a_range) {
9822cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9823cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 VALIDATION_ERROR_00988, "DS",
9824cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "vkCmdPushConstants() Push constant range [%d, %d) "
9825cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "with stageFlags = 0x%" PRIx32
9826cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 " "
9827cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "not within flag-matching ranges in pipeline layout 0x%" PRIx64 ". %s",
9828cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 offset, offset + size, (uint32_t)stageFlags, (uint64_t)layout,
9829cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 validation_error_map[VALIDATION_ERROR_00988]);
983015a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        }
98315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9832b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
9833cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdPushConstants(commandBuffer, layout, stageFlags, offset, size, pValues);
98345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
98355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9836bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage,
9837bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                             VkQueryPool queryPool, uint32_t slot) {
983883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
98395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
9840b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
98415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
98425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
98435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        QueryObject query = {queryPool, slot};
9844c2ec509029604290e981885108c06a9b7de565c1Karl Schultz        std::function<bool(VkQueue)> queryUpdate = std::bind(setQueryState, std::placeholders::_1, commandBuffer, query, true);
9845d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        pCB->queryUpdates.push_back(queryUpdate);
98465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (pCB->state == CB_RECORDING) {
984729f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis            skip_call |= ValidateCmd(dev_data, pCB, CMD_WRITETIMESTAMP, "vkCmdWriteTimestamp()");
984829f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis            UpdateCmdBufferLastCmd(dev_data, pCB, CMD_WRITETIMESTAMP);
98495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
985083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdWriteTimestamp()");
98515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
98525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9853b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
9854cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdWriteTimestamp(commandBuffer, pipelineStage, queryPool, slot);
98555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
98565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
98576600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinskistatic bool MatchUsage(layer_data *dev_data, uint32_t count, const VkAttachmentReference *attachments,
98589bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                       const VkFramebufferCreateInfo *fbci, VkImageUsageFlagBits usage_flag,
98599bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                       UNIQUE_VALIDATION_ERROR_CODE error_code) {
98606600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    bool skip_call = false;
98616600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
98626600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    for (uint32_t attach = 0; attach < count; attach++) {
98636600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski        if (attachments[attach].attachment != VK_ATTACHMENT_UNUSED) {
98646600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            // Attachment counts are verified elsewhere, but prevent an invalid access
98656600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            if (attachments[attach].attachment < fbci->attachmentCount) {
98666600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                const VkImageView *image_view = &fbci->pAttachments[attachments[attach].attachment];
986779fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                auto view_state = getImageViewState(dev_data, *image_view);
986879fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if (view_state) {
98691facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis                    const VkImageCreateInfo *ici = &getImageState(dev_data, view_state->create_info.image)->createInfo;
98706600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                    if (ici != nullptr) {
98716600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                        if ((ici->usage & usage_flag) == 0) {
98726600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
98739bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                                 (VkDebugReportObjectTypeEXT)0, 0, __LINE__, error_code, "DS",
98746600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                                                 "vkCreateFramebuffer:  Framebuffer Attachment (%d) conflicts with the image's "
98759bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                                 "IMAGE_USAGE flags (%s). %s",
98769bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                                 attachments[attach].attachment, string_VkImageUsageFlagBits(usage_flag),
98779bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                                 validation_error_map[error_code]);
98786600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                        }
98796600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                    }
98806600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                }
98816600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            }
98826600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski        }
98836600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    }
98846600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    return skip_call;
98856600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski}
98866600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
9887d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis// Validate VkFramebufferCreateInfo which includes:
9888d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis// 1. attachmentCount equals renderPass attachmentCount
98895ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 2. corresponding framebuffer and renderpass attachments have matching formats
98905ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 3. corresponding framebuffer and renderpass attachments have matching sample counts
98915ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 4. fb attachments only have a single mip level
98925ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 5. fb attachment dimensions are each at least as large as the fb
98935ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 6. fb attachments use idenity swizzle
98945ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 7. fb attachments used by renderPass for color/input/ds have correct usage bit set
98956fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis// 8. fb dimensions are within physical device limits
9896d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlisstatic bool ValidateFramebufferCreateInfo(layer_data *dev_data, const VkFramebufferCreateInfo *pCreateInfo) {
98976600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    bool skip_call = false;
98986600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
9899127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis    auto rp_state = getRenderPassState(dev_data, pCreateInfo->renderPass);
9900127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis    if (rp_state) {
9901127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis        const VkRenderPassCreateInfo *rpci = rp_state->createInfo.ptr();
9902d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis        if (rpci->attachmentCount != pCreateInfo->attachmentCount) {
9903d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis            skip_call |= log_msg(
9904d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
99059bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                reinterpret_cast<const uint64_t &>(pCreateInfo->renderPass), __LINE__, VALIDATION_ERROR_00404, "DS",
9906d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis                "vkCreateFramebuffer(): VkFramebufferCreateInfo attachmentCount of %u does not match attachmentCount of %u of "
99079bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                "renderPass (0x%" PRIxLEAST64 ") being used to create Framebuffer. %s",
99089bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                pCreateInfo->attachmentCount, rpci->attachmentCount, reinterpret_cast<const uint64_t &>(pCreateInfo->renderPass),
99099bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                validation_error_map[VALIDATION_ERROR_00404]);
99105ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis        } else {
991141ebcb6b517b1de5ae456d46d866f5e84a96a2c5Tobin Ehlis            // attachmentCounts match, so make sure corresponding attachment details line up
99125ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis            const VkImageView *image_views = pCreateInfo->pAttachments;
99135ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis            for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
991479fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                auto view_state = getImageViewState(dev_data, image_views[i]);
991512d5600c2f9e32343016fd944432ba95df370797Tobin Ehlis                auto &ivci = view_state->create_info;
991679fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if (ivci.format != rpci->pAttachments[i].format) {
99175ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                    skip_call |= log_msg(
99185ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
99199bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        reinterpret_cast<const uint64_t &>(pCreateInfo->renderPass), __LINE__, VALIDATION_ERROR_00408, "DS",
99209bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has format of %s that does not match "
99219bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "the format of "
99229bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "%s used by the corresponding attachment for renderPass (0x%" PRIxLEAST64 "). %s",
992379fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                        i, string_VkFormat(ivci.format), string_VkFormat(rpci->pAttachments[i].format),
99249bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        reinterpret_cast<const uint64_t &>(pCreateInfo->renderPass), validation_error_map[VALIDATION_ERROR_00408]);
99255ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
99261facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis                const VkImageCreateInfo *ici = &getImageState(dev_data, ivci.image)->createInfo;
99275ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                if (ici->samples != rpci->pAttachments[i].samples) {
992841ebcb6b517b1de5ae456d46d866f5e84a96a2c5Tobin Ehlis                    skip_call |= log_msg(
992941ebcb6b517b1de5ae456d46d866f5e84a96a2c5Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
99309bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        reinterpret_cast<const uint64_t &>(pCreateInfo->renderPass), __LINE__, VALIDATION_ERROR_00409, "DS",
99319bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has %s samples that do not match "
99329bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "the %s samples used by the corresponding attachment for renderPass (0x%" PRIxLEAST64 "). %s",
993341ebcb6b517b1de5ae456d46d866f5e84a96a2c5Tobin Ehlis                        i, string_VkSampleCountFlagBits(ici->samples), string_VkSampleCountFlagBits(rpci->pAttachments[i].samples),
99349bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        reinterpret_cast<const uint64_t &>(pCreateInfo->renderPass), validation_error_map[VALIDATION_ERROR_00409]);
99355ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
99365ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                // Verify that view only has a single mip level
993779fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if (ivci.subresourceRange.levelCount != 1) {
99389bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                    skip_call |=
99399bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
99409bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                VALIDATION_ERROR_00411, "DS",
99419bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has mip levelCount of %u "
99429bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                "but only a single mip level (levelCount ==  1) is allowed when creating a Framebuffer. %s",
99439bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                i, ivci.subresourceRange.levelCount, validation_error_map[VALIDATION_ERROR_00411]);
99445ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
994579fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                const uint32_t mip_level = ivci.subresourceRange.baseMipLevel;
9946aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                uint32_t mip_width = max(1u, ici->extent.width >> mip_level);
9947aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                uint32_t mip_height = max(1u, ici->extent.height >> mip_level);
994879fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if ((ivci.subresourceRange.layerCount < pCreateInfo->layers) || (mip_width < pCreateInfo->width) ||
9949aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                    (mip_height < pCreateInfo->height)) {
9950aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                    skip_call |=
99516fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
9952aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                DRAWSTATE_INVALID_FRAMEBUFFER_CREATE_INFO, "DS",
9953aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u mip level %u has dimensions smaller "
9954aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                "than the corresponding "
9955aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                "framebuffer dimensions. Attachment dimensions must be at least as large. Here are the respective "
9956aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                "dimensions for "
9957aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                "attachment #%u, framebuffer:\n"
9958aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                "width: %u, %u\n"
9959aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                "height: %u, %u\n"
9960aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                "layerCount: %u, %u\n",
996179fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                                i, ivci.subresourceRange.baseMipLevel, i, mip_width, pCreateInfo->width, mip_height,
996279fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                                pCreateInfo->height, ivci.subresourceRange.layerCount, pCreateInfo->layers);
99635ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
996479fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if (((ivci.components.r != VK_COMPONENT_SWIZZLE_IDENTITY) && (ivci.components.r != VK_COMPONENT_SWIZZLE_R)) ||
996579fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                    ((ivci.components.g != VK_COMPONENT_SWIZZLE_IDENTITY) && (ivci.components.g != VK_COMPONENT_SWIZZLE_G)) ||
996679fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                    ((ivci.components.b != VK_COMPONENT_SWIZZLE_IDENTITY) && (ivci.components.b != VK_COMPONENT_SWIZZLE_B)) ||
996779fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                    ((ivci.components.a != VK_COMPONENT_SWIZZLE_IDENTITY) && (ivci.components.a != VK_COMPONENT_SWIZZLE_A))) {
9968da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                    skip_call |= log_msg(
99696fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
99709bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        VALIDATION_ERROR_00412, "DS",
9971da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has non-identy swizzle. All framebuffer "
9972da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "attachments must have been created with the identity swizzle. Here are the actual swizzle values:\n"
9973da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "r swizzle = %s\n"
9974da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "g swizzle = %s\n"
9975da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "b swizzle = %s\n"
99769bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "a swizzle = %s\n"
99779bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "%s",
997879fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                        i, string_VkComponentSwizzle(ivci.components.r), string_VkComponentSwizzle(ivci.components.g),
99799bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        string_VkComponentSwizzle(ivci.components.b), string_VkComponentSwizzle(ivci.components.a),
99809bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        validation_error_map[VALIDATION_ERROR_00412]);
99815ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
99825ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis            }
9983d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis        }
99845ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis        // Verify correct attachment usage flags
99856600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski        for (uint32_t subpass = 0; subpass < rpci->subpassCount; subpass++) {
99866600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            // Verify input attachments:
99879bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt            skip_call |=
99889bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                MatchUsage(dev_data, rpci->pSubpasses[subpass].inputAttachmentCount, rpci->pSubpasses[subpass].pInputAttachments,
99899bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                           pCreateInfo, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, VALIDATION_ERROR_00407);
99906600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            // Verify color attachments:
99919bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt            skip_call |=
99929bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                MatchUsage(dev_data, rpci->pSubpasses[subpass].colorAttachmentCount, rpci->pSubpasses[subpass].pColorAttachments,
99939bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                           pCreateInfo, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VALIDATION_ERROR_00405);
99946600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            // Verify depth/stencil attachments:
99956600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            if (rpci->pSubpasses[subpass].pDepthStencilAttachment != nullptr) {
99966600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                skip_call |= MatchUsage(dev_data, 1, rpci->pSubpasses[subpass].pDepthStencilAttachment, pCreateInfo,
99979bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                        VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VALIDATION_ERROR_00406);
99986600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            }
99996600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski        }
100006600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    }
100016fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis    // Verify FB dimensions are within physical device limits
100029bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    if (pCreateInfo->width > dev_data->phys_dev_properties.properties.limits.maxFramebufferWidth) {
100036fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
100049bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             VALIDATION_ERROR_00413, "DS",
100059bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo width exceeds physical device limits. "
100069bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "Requested width: %u, device max: %u\n"
100079bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "%s",
100086fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis                             pCreateInfo->width, dev_data->phys_dev_properties.properties.limits.maxFramebufferWidth,
100099bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             validation_error_map[VALIDATION_ERROR_00413]);
100109bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    }
100119bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    if (pCreateInfo->height > dev_data->phys_dev_properties.properties.limits.maxFramebufferHeight) {
100129bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
100139bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             VALIDATION_ERROR_00414, "DS",
100149bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo height exceeds physical device limits. "
100159bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "Requested height: %u, device max: %u\n"
100169bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "%s",
100176fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis                             pCreateInfo->height, dev_data->phys_dev_properties.properties.limits.maxFramebufferHeight,
100189bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             validation_error_map[VALIDATION_ERROR_00414]);
100199bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    }
100209bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    if (pCreateInfo->layers > dev_data->phys_dev_properties.properties.limits.maxFramebufferLayers) {
100219bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
100229bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             VALIDATION_ERROR_00415, "DS",
100239bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo layers exceeds physical device limits. "
100249bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "Requested layers: %u, device max: %u\n"
100259bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "%s",
100269bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             pCreateInfo->layers, dev_data->phys_dev_properties.properties.limits.maxFramebufferLayers,
100279bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             validation_error_map[VALIDATION_ERROR_00415]);
100286fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis    }
100296600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    return skip_call;
100306600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski}
100316600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
1003264c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis// Validate VkFramebufferCreateInfo state prior to calling down chain to create Framebuffer object
1003364c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis//  Return true if an error is encountered and callback returns true to skip call down chain
1003464c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis//   false indicates that call down chain should proceed
1003564c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlisstatic bool PreCallValidateCreateFramebuffer(layer_data *dev_data, const VkFramebufferCreateInfo *pCreateInfo) {
1003664c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    // TODO : Verify that renderPass FB is created with is compatible with FB
1003764c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    bool skip_call = false;
10038d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis    skip_call |= ValidateFramebufferCreateInfo(dev_data, pCreateInfo);
1003964c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    return skip_call;
1004064c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis}
1004164c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis
1004254e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis// CreateFramebuffer state has been validated and call down chain completed so record new framebuffer object
1004354e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlisstatic void PostCallRecordCreateFramebuffer(layer_data *dev_data, const VkFramebufferCreateInfo *pCreateInfo, VkFramebuffer fb) {
1004454e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis    // Shadow create info and store in map
10045c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    std::unique_ptr<FRAMEBUFFER_STATE> fb_state(
10046c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis        new FRAMEBUFFER_STATE(fb, pCreateInfo, dev_data->renderPassMap[pCreateInfo->renderPass]->createInfo.ptr()));
1004776f04ca0e692f9f15d5ef7e0c658c24d11f34ebcTobin Ehlis
1004854e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
1004954e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        VkImageView view = pCreateInfo->pAttachments[i];
1005079fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis        auto view_state = getImageViewState(dev_data, view);
1005179fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis        if (!view_state) {
1005254e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis            continue;
1005354e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        }
1005454e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        MT_FB_ATTACHMENT_INFO fb_info;
10055e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis        fb_info.mem = getImageState(dev_data, view_state->create_info.image)->binding.mem;
10056883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        fb_info.view_state = view_state;
1005779fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis        fb_info.image = view_state->create_info.image;
10058c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis        fb_state->attachments.push_back(fb_info);
1005954e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis    }
10060c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    dev_data->frameBufferMap[fb] = std::move(fb_state);
1006154e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis}
1006254e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis
1006389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateFramebuffer(VkDevice device, const VkFramebufferCreateInfo *pCreateInfo,
10064bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkAllocationCallbacks *pAllocator, VkFramebuffer *pFramebuffer) {
100655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
1006664c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
1006764c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    bool skip_call = PreCallValidateCreateFramebuffer(dev_data, pCreateInfo);
1006864c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    lock.unlock();
1006964c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis
10070cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
1007164c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis
100724a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateFramebuffer(device, pCreateInfo, pAllocator, pFramebuffer);
100736600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
100745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
1007564c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis        lock.lock();
1007654e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        PostCallRecordCreateFramebuffer(dev_data, pCreateInfo, *pFramebuffer);
1007754e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        lock.unlock();
100785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
100795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
100805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
100815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10082e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool FindDependency(const int index, const int dependent, const std::vector<DAGNode> &subpass_to_node,
10083e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                           std::unordered_set<uint32_t> &processed_nodes) {
100845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If we have already checked this node we have not found a dependency path so return false.
10085cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (processed_nodes.count(index)) return false;
100865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    processed_nodes.insert(index);
100875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    const DAGNode &node = subpass_to_node[index];
100885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Look for a dependency path. If one exists return true else recurse on the previous nodes.
10089593f84b63934f07483e5e5a20fd352df8ab4f8c9Bruce Dawson    if (std::find(node.prev.begin(), node.prev.end(), static_cast<uint32_t>(dependent)) == node.prev.end()) {
100905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto elem : node.prev) {
10091cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (FindDependency(elem, dependent, subpass_to_node, processed_nodes)) return true;
100925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
100935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
10094e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        return true;
100955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10096e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    return false;
100975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
100985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
100998860b85a52096f9f9b28616bc37feed505497a54Chris Forbesstatic bool CheckDependencyExists(const layer_data *dev_data, const int subpass, const std::vector<uint32_t> &dependent_subpasses,
10100e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                                  const std::vector<DAGNode> &subpass_to_node, bool &skip_call) {
10101e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool result = true;
101025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Loop through all subpasses that share the same attachment and make sure a dependency exists
101035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t k = 0; k < dependent_subpasses.size(); ++k) {
10104cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (static_cast<uint32_t>(subpass) == dependent_subpasses[k]) continue;
101055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const DAGNode &node = subpass_to_node[subpass];
101065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Check for a specified dependency between the two nodes. If one exists we are done.
101075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto prev_elem = std::find(node.prev.begin(), node.prev.end(), dependent_subpasses[k]);
101085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto next_elem = std::find(node.next.begin(), node.next.end(), dependent_subpasses[k]);
101095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (prev_elem == node.prev.end() && next_elem == node.next.end()) {
101107655cb8b5eb52badee0b011729a05afa36316d69Jan-Harald Fredriksen            // If no dependency exits an implicit dependency still might. If not, throw an error.
101115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            std::unordered_set<uint32_t> processed_nodes;
101127655cb8b5eb52badee0b011729a05afa36316d69Jan-Harald Fredriksen            if (!(FindDependency(subpass, dependent_subpasses[k], subpass_to_node, processed_nodes) ||
10113bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                  FindDependency(dependent_subpasses[k], subpass, subpass_to_node, processed_nodes))) {
101148860b85a52096f9f9b28616bc37feed505497a54Chris Forbes                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
101155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                     __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
101165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                     "A dependency between subpasses %d and %d must exist but one is not specified.", subpass,
101175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                     dependent_subpasses[k]);
10118e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                result = false;
101195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
101205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
101215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
101225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
101235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
101245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
101258860b85a52096f9f9b28616bc37feed505497a54Chris Forbesstatic bool CheckPreserved(const layer_data *dev_data, const VkRenderPassCreateInfo *pCreateInfo, const int index,
10126e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                           const uint32_t attachment, const std::vector<DAGNode> &subpass_to_node, int depth, bool &skip_call) {
101275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    const DAGNode &node = subpass_to_node[index];
101285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If this node writes to the attachment return true as next nodes need to preserve the attachment.
101295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[index];
101305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
10131cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (attachment == subpass.pColorAttachments[j].attachment) return true;
101325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
101335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
10134cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (attachment == subpass.pDepthStencilAttachment->attachment) return true;
101355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10136e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool result = false;
101375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Loop through previous nodes and see if any of them write to the attachment.
101385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto elem : node.prev) {
101398860b85a52096f9f9b28616bc37feed505497a54Chris Forbes        result |= CheckPreserved(dev_data, pCreateInfo, elem, attachment, subpass_to_node, depth + 1, skip_call);
101405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
101415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If the attachment was written to by a previous node than this node needs to preserve it.
101425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result && depth > 0) {
10143e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        bool has_preserved = false;
101445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.preserveAttachmentCount; ++j) {
101455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (subpass.pPreserveAttachments[j] == attachment) {
10146e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                has_preserved = true;
101475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                break;
101485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
101495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
10150e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        if (!has_preserved) {
101515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            skip_call |=
101528860b85a52096f9f9b28616bc37feed505497a54Chris Forbes                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
101535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        DRAWSTATE_INVALID_RENDERPASS, "DS",
101545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        "Attachment %d is used by a later subpass and must be preserved in subpass %d.", attachment, index);
101555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
101565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
101575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
101585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
101595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10160cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskitemplate <class T>
10161cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskibool isRangeOverlapping(T offset1, T size1, T offset2, T size2) {
101625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return (((offset1 + size1) > offset2) && ((offset1 + size1) < (offset2 + size2))) ||
101635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis           ((offset1 > offset2) && (offset1 < (offset2 + size2)));
101645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
101655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
101665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisbool isRegionOverlapping(VkImageSubresourceRange range1, VkImageSubresourceRange range2) {
101675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return (isRangeOverlapping(range1.baseMipLevel, range1.levelCount, range2.baseMipLevel, range2.levelCount) &&
101685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            isRangeOverlapping(range1.baseArrayLayer, range1.layerCount, range2.baseArrayLayer, range2.layerCount));
101695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
101705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10171c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlisstatic bool ValidateDependencies(const layer_data *dev_data, FRAMEBUFFER_STATE const *framebuffer,
10172127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                                 RENDER_PASS_STATE const *renderPass) {
10173e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
10174fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    auto const pFramebufferInfo = framebuffer->createInfo.ptr();
10175fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    auto const pCreateInfo = renderPass->createInfo.ptr();
10176bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto const &subpass_to_node = renderPass->subpassToNode;
101775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<std::vector<uint32_t>> output_attachment_to_subpass(pCreateInfo->attachmentCount);
101785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<std::vector<uint32_t>> input_attachment_to_subpass(pCreateInfo->attachmentCount);
101795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<std::vector<uint32_t>> overlapping_attachments(pCreateInfo->attachmentCount);
101805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Find overlapping attachments
101815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
101825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = i + 1; j < pCreateInfo->attachmentCount; ++j) {
101835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            VkImageView viewi = pFramebufferInfo->pAttachments[i];
101845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            VkImageView viewj = pFramebufferInfo->pAttachments[j];
101855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (viewi == viewj) {
101865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[i].push_back(j);
101875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[j].push_back(i);
101885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                continue;
101895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
101908860b85a52096f9f9b28616bc37feed505497a54Chris Forbes            auto view_state_i = getImageViewState(dev_data, viewi);
101918860b85a52096f9f9b28616bc37feed505497a54Chris Forbes            auto view_state_j = getImageViewState(dev_data, viewj);
1019279fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis            if (!view_state_i || !view_state_j) {
101935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                continue;
101945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
1019579fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis            auto view_ci_i = view_state_i->create_info;
1019679fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis            auto view_ci_j = view_state_j->create_info;
1019779fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis            if (view_ci_i.image == view_ci_j.image && isRegionOverlapping(view_ci_i.subresourceRange, view_ci_j.subresourceRange)) {
101985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[i].push_back(j);
101995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[j].push_back(i);
102005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                continue;
102015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
102021facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            auto image_data_i = getImageState(dev_data, view_ci_i.image);
102031facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            auto image_data_j = getImageState(dev_data, view_ci_j.image);
102046d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            if (!image_data_i || !image_data_j) {
102055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                continue;
102065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
10207e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis            if (image_data_i->binding.mem == image_data_j->binding.mem &&
10208e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis                isRangeOverlapping(image_data_i->binding.offset, image_data_i->binding.size, image_data_j->binding.offset,
10209e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis                                   image_data_j->binding.size)) {
102105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[i].push_back(j);
102115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[j].push_back(i);
102125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
102135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
102145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
102155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < overlapping_attachments.size(); ++i) {
102165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t attachment = i;
102175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto other_attachment : overlapping_attachments[i]) {
102185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!(pCreateInfo->pAttachments[attachment].flags & VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT)) {
102199bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
10220cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     __LINE__, VALIDATION_ERROR_00324, "DS",
10221cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "Attachment %d aliases attachment %d but doesn't "
10222cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "set VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT. %s",
102239bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                     attachment, other_attachment, validation_error_map[VALIDATION_ERROR_00324]);
102245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
102255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!(pCreateInfo->pAttachments[other_attachment].flags & VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT)) {
102269bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
10227cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     __LINE__, VALIDATION_ERROR_00324, "DS",
10228cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "Attachment %d aliases attachment %d but doesn't "
10229cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "set VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT. %s",
102309bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                     other_attachment, attachment, validation_error_map[VALIDATION_ERROR_00324]);
102315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
102325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
102335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
102345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Find for each attachment the subpasses that use them.
102351c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young    unordered_set<uint32_t> attachmentIndices;
102365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
102375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
102381c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young        attachmentIndices.clear();
102395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
102405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t attachment = subpass.pInputAttachments[j].attachment;
10241cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) continue;
102425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            input_attachment_to_subpass[attachment].push_back(i);
102435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            for (auto overlapping_attachment : overlapping_attachments[attachment]) {
102445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                input_attachment_to_subpass[overlapping_attachment].push_back(i);
102455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
102465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
102475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
102485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t attachment = subpass.pColorAttachments[j].attachment;
10249cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) continue;
102505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            output_attachment_to_subpass[attachment].push_back(i);
102515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            for (auto overlapping_attachment : overlapping_attachments[attachment]) {
102525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                output_attachment_to_subpass[overlapping_attachment].push_back(i);
102535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
102541c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young            attachmentIndices.insert(attachment);
102555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
102565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
102575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t attachment = subpass.pDepthStencilAttachment->attachment;
102585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            output_attachment_to_subpass[attachment].push_back(i);
102595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            for (auto overlapping_attachment : overlapping_attachments[attachment]) {
102605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                output_attachment_to_subpass[overlapping_attachment].push_back(i);
102615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
102621c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young
102631c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young            if (attachmentIndices.count(attachment)) {
102641c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young                skip_call |=
102658860b85a52096f9f9b28616bc37feed505497a54Chris Forbes                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
102668860b85a52096f9f9b28616bc37feed505497a54Chris Forbes                            DRAWSTATE_INVALID_RENDERPASS, "DS",
102678860b85a52096f9f9b28616bc37feed505497a54Chris Forbes                            "Cannot use same attachment (%u) as both color and depth output in same subpass (%u).", attachment, i);
102681c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young            }
102695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
102705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
102715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If there is a dependency needed make sure one exists
102725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
102735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
102745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // If the attachment is an input then all subpasses that output must have a dependency relationship
102755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
1027693fe72ec8460857bdb3c101095e6eb96d6171341Chris Forbes            uint32_t attachment = subpass.pInputAttachments[j].attachment;
10277cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) continue;
102788860b85a52096f9f9b28616bc37feed505497a54Chris Forbes            CheckDependencyExists(dev_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip_call);
102795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
102805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // If the attachment is an output then all subpasses that use the attachment must have a dependency relationship
102815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
1028293fe72ec8460857bdb3c101095e6eb96d6171341Chris Forbes            uint32_t attachment = subpass.pColorAttachments[j].attachment;
10283cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) continue;
102848860b85a52096f9f9b28616bc37feed505497a54Chris Forbes            CheckDependencyExists(dev_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip_call);
102858860b85a52096f9f9b28616bc37feed505497a54Chris Forbes            CheckDependencyExists(dev_data, i, input_attachment_to_subpass[attachment], subpass_to_node, skip_call);
102865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
102875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
102885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            const uint32_t &attachment = subpass.pDepthStencilAttachment->attachment;
102898860b85a52096f9f9b28616bc37feed505497a54Chris Forbes            CheckDependencyExists(dev_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip_call);
102908860b85a52096f9f9b28616bc37feed505497a54Chris Forbes            CheckDependencyExists(dev_data, i, input_attachment_to_subpass[attachment], subpass_to_node, skip_call);
102915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
102925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
102935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Loop through implicit dependencies, if this pass reads make sure the attachment is preserved for all passes after it was
102945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // written.
102955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
102965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
102975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
102988860b85a52096f9f9b28616bc37feed505497a54Chris Forbes            CheckPreserved(dev_data, pCreateInfo, i, subpass.pInputAttachments[j].attachment, subpass_to_node, 0, skip_call);
102995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
103005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
103015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
103025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
10303be45dd763c94dfcb0b52709d8d613848c4c914e1Tobin Ehlis// ValidateLayoutVsAttachmentDescription is a general function where we can validate various state associated with the
10304be45dd763c94dfcb0b52709d8d613848c4c914e1Tobin Ehlis// VkAttachmentDescription structs that are used by the sub-passes of a renderpass. Initial check is to make sure that
10305be45dd763c94dfcb0b52709d8d613848c4c914e1Tobin Ehlis// READ_ONLY layout attachments don't have CLEAR as their loadOp.
10306be45dd763c94dfcb0b52709d8d613848c4c914e1Tobin Ehlisstatic bool ValidateLayoutVsAttachmentDescription(debug_report_data *report_data, const VkImageLayout first_layout,
10307be45dd763c94dfcb0b52709d8d613848c4c914e1Tobin Ehlis                                                  const uint32_t attachment,
10308be45dd763c94dfcb0b52709d8d613848c4c914e1Tobin Ehlis                                                  const VkAttachmentDescription &attachment_description) {
10309be45dd763c94dfcb0b52709d8d613848c4c914e1Tobin Ehlis    bool skip_call = false;
10310be45dd763c94dfcb0b52709d8d613848c4c914e1Tobin Ehlis    // Verify that initial loadOp on READ_ONLY attachments is not CLEAR
10311be45dd763c94dfcb0b52709d8d613848c4c914e1Tobin Ehlis    if (attachment_description.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) {
10312be45dd763c94dfcb0b52709d8d613848c4c914e1Tobin Ehlis        if ((first_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) ||
10313be45dd763c94dfcb0b52709d8d613848c4c914e1Tobin Ehlis            (first_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)) {
103149bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt            skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
103159bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                 VkDebugReportObjectTypeEXT(0), __LINE__, VALIDATION_ERROR_02351, "DS",
103169bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                 "Cannot clear attachment %d with invalid first layout %s. %s", attachment,
103179bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                 string_VkImageLayout(first_layout), validation_error_map[VALIDATION_ERROR_02351]);
10318be45dd763c94dfcb0b52709d8d613848c4c914e1Tobin Ehlis        }
10319be45dd763c94dfcb0b52709d8d613848c4c914e1Tobin Ehlis    }
10320be45dd763c94dfcb0b52709d8d613848c4c914e1Tobin Ehlis    return skip_call;
10321be45dd763c94dfcb0b52709d8d613848c4c914e1Tobin Ehlis}
103225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
103238860b85a52096f9f9b28616bc37feed505497a54Chris Forbesstatic bool ValidateLayouts(const layer_data *dev_data, VkDevice device, const VkRenderPassCreateInfo *pCreateInfo) {
10324e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip = false;
103255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1032677c531defc2e8614acee0969b170cc2fa68f55d3Tobin Ehlis    // Track when we're observing the first use of an attachment
1032777c531defc2e8614acee0969b170cc2fa68f55d3Tobin Ehlis    std::vector<bool> attach_first_use(pCreateInfo->attachmentCount, true);
103285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
103295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
103305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
103310ad39e0de2f23ebec8c8ffbf6b54754ebf5ae9a7Chris Forbes            auto attach_index = subpass.pColorAttachments[j].attachment;
10332cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (attach_index == VK_ATTACHMENT_UNUSED) continue;
103330ad39e0de2f23ebec8c8ffbf6b54754ebf5ae9a7Chris Forbes
10334c74f9e8c7fe6b470f757da0c42367fe725fe0928Chris Forbes            switch (subpass.pColorAttachments[j].layout) {
10335cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
10336cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    // This is ideal.
10337cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
10338c74f9e8c7fe6b470f757da0c42367fe725fe0928Chris Forbes
10339cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_IMAGE_LAYOUT_GENERAL:
10340cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    // May not be optimal; TODO: reconsider this warning based on other constraints?
10341cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
10342cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
10343cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    "Layout for color attachment is GENERAL but should be COLOR_ATTACHMENT_OPTIMAL.");
10344cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
10345c74f9e8c7fe6b470f757da0c42367fe725fe0928Chris Forbes
10346cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                default:
10347cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
10348cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
10349cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    "Layout for color attachment is %s but can only be COLOR_ATTACHMENT_OPTIMAL or GENERAL.",
10350cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    string_VkImageLayout(subpass.pColorAttachments[j].layout));
103515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
10352c74f9e8c7fe6b470f757da0c42367fe725fe0928Chris Forbes
1035377c531defc2e8614acee0969b170cc2fa68f55d3Tobin Ehlis            if (attach_first_use[attach_index]) {
103548860b85a52096f9f9b28616bc37feed505497a54Chris Forbes                skip |= ValidateLayoutVsAttachmentDescription(dev_data->report_data, subpass.pColorAttachments[j].layout,
1035577c531defc2e8614acee0969b170cc2fa68f55d3Tobin Ehlis                                                              attach_index, pCreateInfo->pAttachments[attach_index]);
1035677c531defc2e8614acee0969b170cc2fa68f55d3Tobin Ehlis            }
1035777c531defc2e8614acee0969b170cc2fa68f55d3Tobin Ehlis            attach_first_use[attach_index] = false;
103585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
10359c74f9e8c7fe6b470f757da0c42367fe725fe0928Chris Forbes        if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
10360cfa128db908c2462aaf616950fb2fdb9d2f92bc1Chris Forbes            switch (subpass.pDepthStencilAttachment->layout) {
10361cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
10362cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
10363cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    // These are ideal.
10364cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
10365cfa128db908c2462aaf616950fb2fdb9d2f92bc1Chris Forbes
10366cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_IMAGE_LAYOUT_GENERAL:
10367cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    // May not be optimal; TODO: reconsider this warning based on other constraints? GENERAL can be better than
10368cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    // doing
10369cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    // a bunch of transitions.
10370cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
10371cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
10372cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    "GENERAL layout for depth attachment may not give optimal performance.");
10373cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
10374cfa128db908c2462aaf616950fb2fdb9d2f92bc1Chris Forbes
10375cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                default:
10376cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    // No other layouts are acceptable
10377cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
10378cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
10379cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    "Layout for depth attachment is %s but can only be DEPTH_STENCIL_ATTACHMENT_OPTIMAL, "
10380cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    "DEPTH_STENCIL_READ_ONLY_OPTIMAL or GENERAL.",
10381cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    string_VkImageLayout(subpass.pDepthStencilAttachment->layout));
103825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
10383cfa128db908c2462aaf616950fb2fdb9d2f92bc1Chris Forbes
10384be45dd763c94dfcb0b52709d8d613848c4c914e1Tobin Ehlis            auto attach_index = subpass.pDepthStencilAttachment->attachment;
1038577c531defc2e8614acee0969b170cc2fa68f55d3Tobin Ehlis            if (attach_first_use[attach_index]) {
103868860b85a52096f9f9b28616bc37feed505497a54Chris Forbes                skip |= ValidateLayoutVsAttachmentDescription(dev_data->report_data, subpass.pDepthStencilAttachment->layout,
1038777c531defc2e8614acee0969b170cc2fa68f55d3Tobin Ehlis                                                              attach_index, pCreateInfo->pAttachments[attach_index]);
1038877c531defc2e8614acee0969b170cc2fa68f55d3Tobin Ehlis            }
1038977c531defc2e8614acee0969b170cc2fa68f55d3Tobin Ehlis            attach_first_use[attach_index] = false;
1039077c531defc2e8614acee0969b170cc2fa68f55d3Tobin Ehlis        }
1039177c531defc2e8614acee0969b170cc2fa68f55d3Tobin Ehlis        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
1039277c531defc2e8614acee0969b170cc2fa68f55d3Tobin Ehlis            auto attach_index = subpass.pInputAttachments[j].attachment;
10393cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (attach_index == VK_ATTACHMENT_UNUSED) continue;
1039477c531defc2e8614acee0969b170cc2fa68f55d3Tobin Ehlis
10395c74f9e8c7fe6b470f757da0c42367fe725fe0928Chris Forbes            switch (subpass.pInputAttachments[j].layout) {
10396cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
10397cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
10398cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    // These are ideal.
10399cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
10400c74f9e8c7fe6b470f757da0c42367fe725fe0928Chris Forbes
10401cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_IMAGE_LAYOUT_GENERAL:
10402cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    // May not be optimal. TODO: reconsider this warning based on other constraints.
10403cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
10404cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
10405cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    "Layout for input attachment is GENERAL but should be READ_ONLY_OPTIMAL.");
10406cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
10407c74f9e8c7fe6b470f757da0c42367fe725fe0928Chris Forbes
10408cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                default:
10409cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    // No other layouts are acceptable
10410cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
10411cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
10412cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    "Layout for input attachment is %s but can only be READ_ONLY_OPTIMAL or GENERAL.",
10413cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    string_VkImageLayout(subpass.pInputAttachments[j].layout));
1041477c531defc2e8614acee0969b170cc2fa68f55d3Tobin Ehlis            }
10415c74f9e8c7fe6b470f757da0c42367fe725fe0928Chris Forbes
1041677c531defc2e8614acee0969b170cc2fa68f55d3Tobin Ehlis            if (attach_first_use[attach_index]) {
104178860b85a52096f9f9b28616bc37feed505497a54Chris Forbes                skip |= ValidateLayoutVsAttachmentDescription(dev_data->report_data, subpass.pInputAttachments[j].layout,
1041877c531defc2e8614acee0969b170cc2fa68f55d3Tobin Ehlis                                                              attach_index, pCreateInfo->pAttachments[attach_index]);
1041977c531defc2e8614acee0969b170cc2fa68f55d3Tobin Ehlis            }
1042077c531defc2e8614acee0969b170cc2fa68f55d3Tobin Ehlis            attach_first_use[attach_index] = false;
104215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
104225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
104235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip;
104245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
104255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
104268860b85a52096f9f9b28616bc37feed505497a54Chris Forbesstatic bool CreatePassDAG(const layer_data *dev_data, VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
10427e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                          std::vector<DAGNode> &subpass_to_node, std::vector<bool> &has_self_dependency) {
10428e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
104295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
104305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        DAGNode &subpass_node = subpass_to_node[i];
104315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        subpass_node.pass = i;
104325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
104335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->dependencyCount; ++i) {
104345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubpassDependency &dependency = pCreateInfo->pDependencies[i];
1043566a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes        if (dependency.srcSubpass == VK_SUBPASS_EXTERNAL || dependency.dstSubpass == VK_SUBPASS_EXTERNAL) {
1043666a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes            if (dependency.srcSubpass == dependency.dstSubpass) {
1043766a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes                skip_call |=
104388860b85a52096f9f9b28616bc37feed505497a54Chris Forbes                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
1043966a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes                            DRAWSTATE_INVALID_RENDERPASS, "DS", "The src and dest subpasses cannot both be external.");
1044066a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes            }
1044166a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes        } else if (dependency.srcSubpass > dependency.dstSubpass) {
104428860b85a52096f9f9b28616bc37feed505497a54Chris Forbes            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
104435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                 DRAWSTATE_INVALID_RENDERPASS, "DS",
104445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                 "Depedency graph must be specified such that an earlier pass cannot depend on a later pass.");
104455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (dependency.srcSubpass == dependency.dstSubpass) {
104465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            has_self_dependency[dependency.srcSubpass] = true;
104475c6aacf95832467d52b2fde1130b04bef559573aChris Forbes        } else {
104485c6aacf95832467d52b2fde1130b04bef559573aChris Forbes            subpass_to_node[dependency.dstSubpass].prev.push_back(dependency.srcSubpass);
104495c6aacf95832467d52b2fde1130b04bef559573aChris Forbes            subpass_to_node[dependency.srcSubpass].next.push_back(dependency.dstSubpass);
104505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
104515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
104525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
104535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
10454918c283ac4f8c604b79abd0c8b5706d2a7352a34Chris Forbes
1045589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo,
10456bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                  const VkAllocationCallbacks *pAllocator, VkShaderModule *pShaderModule) {
104578860b85a52096f9f9b28616bc37feed505497a54Chris Forbes    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
10458e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
10459b1f65702539fd041337fccd493dc6d38dd2a603eChris Forbes
1046025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Use SPIRV-Tools validator to try and catch any issues with the module itself
10461b1f65702539fd041337fccd493dc6d38dd2a603eChris Forbes    spv_context ctx = spvContextCreate(SPV_ENV_VULKAN_1_0);
10462bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    spv_const_binary_t binary{pCreateInfo->pCode, pCreateInfo->codeSize / sizeof(uint32_t)};
10463b1f65702539fd041337fccd493dc6d38dd2a603eChris Forbes    spv_diagnostic diag = nullptr;
10464b1f65702539fd041337fccd493dc6d38dd2a603eChris Forbes
10465b1f65702539fd041337fccd493dc6d38dd2a603eChris Forbes    auto result = spvValidate(ctx, &binary, &diag);
10466b1f65702539fd041337fccd493dc6d38dd2a603eChris Forbes    if (result != SPV_SUCCESS) {
104678860b85a52096f9f9b28616bc37feed505497a54Chris Forbes        skip_call |=
104688860b85a52096f9f9b28616bc37feed505497a54Chris Forbes            log_msg(dev_data->report_data, result == SPV_WARNING ? VK_DEBUG_REPORT_WARNING_BIT_EXT : VK_DEBUG_REPORT_ERROR_BIT_EXT,
104698860b85a52096f9f9b28616bc37feed505497a54Chris Forbes                    VkDebugReportObjectTypeEXT(0), 0, __LINE__, SHADER_CHECKER_INCONSISTENT_SPIRV, "SC",
104708860b85a52096f9f9b28616bc37feed505497a54Chris Forbes                    "SPIR-V module not valid: %s", diag && diag->error ? diag->error : "(no error text)");
104715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
104725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10473b1f65702539fd041337fccd493dc6d38dd2a603eChris Forbes    spvDiagnosticDestroy(diag);
10474b1f65702539fd041337fccd493dc6d38dd2a603eChris Forbes    spvContextDestroy(ctx);
10475b1f65702539fd041337fccd493dc6d38dd2a603eChris Forbes
10476cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
104775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
104784a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult res = dev_data->dispatch_table.CreateShaderModule(device, pCreateInfo, pAllocator, pShaderModule);
104795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
104805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (res == VK_SUCCESS) {
10481b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
104828860b85a52096f9f9b28616bc37feed505497a54Chris Forbes        dev_data->shaderModuleMap[*pShaderModule] = unique_ptr<shader_module>(new shader_module(pCreateInfo));
104835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
104845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return res;
104855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
104865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
104874f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinskistatic bool ValidateAttachmentIndex(layer_data *dev_data, uint32_t attachment, uint32_t attachment_count, const char *type) {
104884f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    bool skip_call = false;
104894f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    if (attachment >= attachment_count && attachment != VK_ATTACHMENT_UNUSED) {
104904f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
10491e52ca7be57745459d6aa4903a3880fc8eaa9d3dcChris Forbes                             VALIDATION_ERROR_00325, "DS",
10492bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             "CreateRenderPass: %s attachment %d must be less than the total number of attachments %d. %s", type,
10493bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             attachment, attachment_count, validation_error_map[VALIDATION_ERROR_00325]);
104944f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    }
104954f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    return skip_call;
104964f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski}
104974f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
10498bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool IsPowerOfTwo(unsigned x) { return x && !(x & (x - 1)); }
10499805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
105004f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinskistatic bool ValidateRenderpassAttachmentUsage(layer_data *dev_data, const VkRenderPassCreateInfo *pCreateInfo) {
105014f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    bool skip_call = false;
105024f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
105034f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
105044f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        if (subpass.pipelineBindPoint != VK_PIPELINE_BIND_POINT_GRAPHICS) {
105059bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
105069bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                 VALIDATION_ERROR_00347, "DS",
105079bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                 "CreateRenderPass: Pipeline bind point for subpass %d must be VK_PIPELINE_BIND_POINT_GRAPHICS. %s",
105089bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                 i, validation_error_map[VALIDATION_ERROR_00347]);
105094f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
105104f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        for (uint32_t j = 0; j < subpass.preserveAttachmentCount; ++j) {
105114f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            uint32_t attachment = subpass.pPreserveAttachments[j];
105124f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) {
105134f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
105149bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                     __LINE__, VALIDATION_ERROR_00356, "DS",
105159bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                     "CreateRenderPass:  Preserve attachment (%d) must not be VK_ATTACHMENT_UNUSED. %s", j,
105169bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                     validation_error_map[VALIDATION_ERROR_00356]);
105174f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            } else {
105184f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                skip_call |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Preserve");
105194f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            }
105204f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
105216a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes
10522bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto subpass_performs_resolve =
10523bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            subpass.pResolveAttachments &&
10524bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            std::any_of(subpass.pResolveAttachments, subpass.pResolveAttachments + subpass.colorAttachmentCount,
10525bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        [](VkAttachmentReference ref) { return ref.attachment != VK_ATTACHMENT_UNUSED; });
105266a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes
10527805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes        unsigned sample_count = 0;
10528805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
105294f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
105304f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            uint32_t attachment;
105314f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            if (subpass.pResolveAttachments) {
105324f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                attachment = subpass.pResolveAttachments[j].attachment;
105334f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                skip_call |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Resolve");
105346a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes
105356a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes                if (!skip_call && attachment != VK_ATTACHMENT_UNUSED &&
105366a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes                    pCreateInfo->pAttachments[attachment].samples != VK_SAMPLE_COUNT_1_BIT) {
105376a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
105389bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         __LINE__, VALIDATION_ERROR_00352, "DS",
105396a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes                                         "CreateRenderPass:  Subpass %u requests multisample resolve into attachment %u, "
105409bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         "which must have VK_SAMPLE_COUNT_1_BIT but has %s. %s",
105419bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         i, attachment, string_VkSampleCountFlagBits(pCreateInfo->pAttachments[attachment].samples),
105429bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         validation_error_map[VALIDATION_ERROR_00352]);
105436a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes                }
105444f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            }
105454f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            attachment = subpass.pColorAttachments[j].attachment;
105464f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            skip_call |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Color");
105476a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes
10548805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes            if (!skip_call && attachment != VK_ATTACHMENT_UNUSED) {
10549805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes                sample_count |= (unsigned)pCreateInfo->pAttachments[attachment].samples;
10550805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
10551bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (subpass_performs_resolve && pCreateInfo->pAttachments[attachment].samples == VK_SAMPLE_COUNT_1_BIT) {
10552dc7c45f01ae5690f7c969b4760463c1a6bac52d5Chris Forbes                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
105539bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         __LINE__, VALIDATION_ERROR_00351, "DS",
10554dc7c45f01ae5690f7c969b4760463c1a6bac52d5Chris Forbes                                         "CreateRenderPass:  Subpass %u requests multisample resolve from attachment %u "
105559bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         "which has VK_SAMPLE_COUNT_1_BIT. %s",
105569bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         i, attachment, validation_error_map[VALIDATION_ERROR_00351]);
10557dc7c45f01ae5690f7c969b4760463c1a6bac52d5Chris Forbes                }
105586a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes            }
105594f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
10560dc7c45f01ae5690f7c969b4760463c1a6bac52d5Chris Forbes
105614f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
105624f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            uint32_t attachment = subpass.pDepthStencilAttachment->attachment;
105634f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            skip_call |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Depth stencil");
10564805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
10565805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes            if (!skip_call && attachment != VK_ATTACHMENT_UNUSED) {
10566805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes                sample_count |= (unsigned)pCreateInfo->pAttachments[attachment].samples;
10567805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes            }
105684f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
10569dc7c45f01ae5690f7c969b4760463c1a6bac52d5Chris Forbes
105704f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
105714f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            uint32_t attachment = subpass.pInputAttachments[j].attachment;
105724f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            skip_call |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Input");
105734f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
10574805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
10575805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes        if (sample_count && !IsPowerOfTwo(sample_count)) {
105769bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
10577cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 VALIDATION_ERROR_00337, "DS",
10578cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "CreateRenderPass:  Subpass %u attempts to render to "
10579cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "attachments with inconsistent sample counts. %s",
105809bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                 i, validation_error_map[VALIDATION_ERROR_00337]);
10581805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes        }
105824f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    }
105834f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    return skip_call;
105844f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski}
105854f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
1058689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
105874f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                                                const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) {
10588e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
105895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
105904f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
105914f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    std::unique_lock<std::mutex> lock(global_lock);
105924f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
105934f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    // TODO: As part of wrapping up the mem_tracker/core_validation merge the following routine should be consolidated with
105944f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    //       ValidateLayouts.
105954f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    skip_call |= ValidateRenderpassAttachmentUsage(dev_data, pCreateInfo);
10596208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->dependencyCount; ++i) {
10597208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip_call |= ValidateStageMaskGsTsEnables(dev_data, pCreateInfo->pDependencies[i].srcStageMask, "vkCreateRenderPass()",
10598208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                                                  VALIDATION_ERROR_00368, VALIDATION_ERROR_00370);
10599208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip_call |= ValidateStageMaskGsTsEnables(dev_data, pCreateInfo->pDependencies[i].dstStageMask, "vkCreateRenderPass()",
10600208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                                                  VALIDATION_ERROR_00369, VALIDATION_ERROR_00371);
10601208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    }
10602ab38df28c5ae1816c5fa33c0c7840c6950e83f0dChris Forbes    if (!skip_call) {
10603ab38df28c5ae1816c5fa33c0c7840c6950e83f0dChris Forbes        skip_call |= ValidateLayouts(dev_data, device, pCreateInfo);
10604ab38df28c5ae1816c5fa33c0c7840c6950e83f0dChris Forbes    }
10605ff6101de02d1677fb54962e2ff57875e76898e26Chris Forbes    lock.unlock();
106064f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
106074f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    if (skip_call) {
106084f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        return VK_ERROR_VALIDATION_FAILED_EXT;
106094f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    }
106104f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
106114a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateRenderPass(device, pCreateInfo, pAllocator, pRenderPass);
10612ff6101de02d1677fb54962e2ff57875e76898e26Chris Forbes
106135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
106144f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        lock.lock();
106154f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
106164f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        std::vector<bool> has_self_dependency(pCreateInfo->subpassCount);
106174f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        std::vector<DAGNode> subpass_to_node(pCreateInfo->subpassCount);
106184f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        skip_call |= CreatePassDAG(dev_data, device, pCreateInfo, subpass_to_node, has_self_dependency);
106194f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
10620127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis        auto render_pass = unique_ptr<RENDER_PASS_STATE>(new RENDER_PASS_STATE(pCreateInfo));
1062198cddf7090b5d5dcc382045867753ef703d1c3d3Chris Forbes        render_pass->renderPass = *pRenderPass;
10622cf2686cdbb12af8a29ca598c126b5e37215f0ef7Chris Forbes        render_pass->hasSelfDependency = has_self_dependency;
10623cf2686cdbb12af8a29ca598c126b5e37215f0ef7Chris Forbes        render_pass->subpassToNode = subpass_to_node;
10624db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes
1062587e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis        // TODO: Maybe fill list and then copy instead of locking
10626cf2686cdbb12af8a29ca598c126b5e37215f0ef7Chris Forbes        std::unordered_map<uint32_t, bool> &attachment_first_read = render_pass->attachment_first_read;
106276600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski        std::unordered_map<uint32_t, VkImageLayout> &attachment_first_layout = render_pass->attachment_first_layout;
1062887e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis        for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
1062987e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis            const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
1063087e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis            for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
106314f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                uint32_t attachment = subpass.pColorAttachments[j].attachment;
106324f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                if (!attachment_first_read.count(attachment)) {
106334f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                    attachment_first_read.insert(std::make_pair(attachment, false));
106344f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                    attachment_first_layout.insert(std::make_pair(attachment, subpass.pColorAttachments[j].layout));
106350d615f0a5724edac98475366cf3e486dccc1f2d6Michael Lentine                }
1063687e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis            }
1063787e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis            if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
1063887e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis                uint32_t attachment = subpass.pDepthStencilAttachment->attachment;
106394f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                if (!attachment_first_read.count(attachment)) {
106404f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                    attachment_first_read.insert(std::make_pair(attachment, false));
106414f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                    attachment_first_layout.insert(std::make_pair(attachment, subpass.pDepthStencilAttachment->layout));
1064224991fb692f7e2d457da50d50c40f2705591300cMichael Lentine                }
1064387e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis            }
10644a5ce96d7c88653668a2b33a6b72bd3cb16d73f48Michael Lentine            for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
10645a5ce96d7c88653668a2b33a6b72bd3cb16d73f48Michael Lentine                uint32_t attachment = subpass.pInputAttachments[j].attachment;
106464f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                if (!attachment_first_read.count(attachment)) {
106474f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                    attachment_first_read.insert(std::make_pair(attachment, true));
106484f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                    attachment_first_layout.insert(std::make_pair(attachment, subpass.pInputAttachments[j].layout));
1064924991fb692f7e2d457da50d50c40f2705591300cMichael Lentine                }
10650a5ce96d7c88653668a2b33a6b72bd3cb16d73f48Michael Lentine            }
1065187e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis        }
10652db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes
10653fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes        dev_data->renderPassMap[*pRenderPass] = std::move(render_pass);
106545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
106555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
106565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
106574f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
10658bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool VerifyFramebufferAndRenderPassLayouts(layer_data *dev_data, GLOBAL_CB_NODE *pCB,
10659bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                  const VkRenderPassBeginInfo *pRenderPassBegin) {
10660e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
10661127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis    auto const pRenderPassInfo = getRenderPassState(dev_data, pRenderPassBegin->renderPass)->createInfo.ptr();
10662bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto const &framebufferInfo = dev_data->frameBufferMap[pRenderPassBegin->framebuffer]->createInfo;
106635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pRenderPassInfo->attachmentCount != framebufferInfo.attachmentCount) {
106645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
10665cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             DRAWSTATE_INVALID_RENDERPASS, "DS",
10666cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "You cannot start a render pass using a framebuffer "
10667cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "with a different number of attachments.");
106685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
106695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pRenderPassInfo->attachmentCount; ++i) {
106705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkImageView &image_view = framebufferInfo.pAttachments[i];
1067179fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis        auto view_state = getImageViewState(dev_data, image_view);
1067279fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis        assert(view_state);
1067379fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis        const VkImage &image = view_state->create_info.image;
1067479fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis        const VkImageSubresourceRange &subRange = view_state->create_info.subresourceRange;
106755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        IMAGE_CMD_BUF_LAYOUT_NODE newNode = {pRenderPassInfo->pAttachments[i].initialLayout,
106765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                             pRenderPassInfo->pAttachments[i].initialLayout};
106775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // TODO: Do not iterate over every possibility - consolidate where possible
106785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subRange.levelCount; j++) {
106795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t level = subRange.baseMipLevel + j;
106805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            for (uint32_t k = 0; k < subRange.layerCount; k++) {
106815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                uint32_t layer = subRange.baseArrayLayer + k;
106825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                VkImageSubresource sub = {subRange.aspectMask, level, layer};
106835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                IMAGE_CMD_BUF_LAYOUT_NODE node;
106845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (!FindLayout(pCB, image, sub, node)) {
106855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    SetLayout(pCB, image, sub, newNode);
106865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    continue;
106875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
10688bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (newNode.layout != VK_IMAGE_LAYOUT_UNDEFINED && newNode.layout != node.layout) {
10689bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
10690bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
10691bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         "You cannot start a render pass using attachment %u "
10692bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         "where the render pass initial layout is %s and the previous "
10693bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         "known layout of the attachment is %s. The layouts must match, or "
10694bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         "the render pass initial layout for the attachment must be "
10695bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         "VK_IMAGE_LAYOUT_UNDEFINED",
10696bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         i, string_VkImageLayout(newNode.layout), string_VkImageLayout(node.layout));
106975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
106985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
106995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
107005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
107015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
107025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
107035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10704c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlisstatic void TransitionAttachmentRefLayout(layer_data *dev_data, GLOBAL_CB_NODE *pCB, FRAMEBUFFER_STATE *pFramebuffer,
10705c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis                                          VkAttachmentReference ref) {
10706628f0e370a17207a87d2632616fc8ca27e7ac80cChris Forbes    if (ref.attachment != VK_ATTACHMENT_UNUSED) {
10707628f0e370a17207a87d2632616fc8ca27e7ac80cChris Forbes        auto image_view = pFramebuffer->createInfo.pAttachments[ref.attachment];
10708628f0e370a17207a87d2632616fc8ca27e7ac80cChris Forbes        SetLayout(dev_data, pCB, image_view, ref.layout);
10709628f0e370a17207a87d2632616fc8ca27e7ac80cChris Forbes    }
10710628f0e370a17207a87d2632616fc8ca27e7ac80cChris Forbes}
10711628f0e370a17207a87d2632616fc8ca27e7ac80cChris Forbes
1071227ed8211a6c2cd0947b7929d0d55d0840618855dChris Forbesstatic void TransitionSubpassLayouts(layer_data *dev_data, GLOBAL_CB_NODE *pCB, const VkRenderPassBeginInfo *pRenderPassBegin,
10713e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                                     const int subpass_index) {
10714127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis    auto renderPass = getRenderPassState(dev_data, pRenderPassBegin->renderPass);
10715cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!renderPass) return;
1071616387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes
10717c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    auto framebuffer = getFramebufferState(dev_data, pRenderPassBegin->framebuffer);
10718cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!framebuffer) return;
10719e3ad4b1284408353cc56a04951c1df1f35a636ceChris Forbes
10720fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    auto const &subpass = renderPass->createInfo.pSubpasses[subpass_index];
107215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
10722628f0e370a17207a87d2632616fc8ca27e7ac80cChris Forbes        TransitionAttachmentRefLayout(dev_data, pCB, framebuffer, subpass.pInputAttachments[j]);
107235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
107245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
10725628f0e370a17207a87d2632616fc8ca27e7ac80cChris Forbes        TransitionAttachmentRefLayout(dev_data, pCB, framebuffer, subpass.pColorAttachments[j]);
107265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10727628f0e370a17207a87d2632616fc8ca27e7ac80cChris Forbes    if (subpass.pDepthStencilAttachment) {
10728628f0e370a17207a87d2632616fc8ca27e7ac80cChris Forbes        TransitionAttachmentRefLayout(dev_data, pCB, framebuffer, *subpass.pDepthStencilAttachment);
107295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
107305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
107315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
107329bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardtstatic bool validatePrimaryCommandBuffer(const layer_data *dev_data, const GLOBAL_CB_NODE *pCB, const std::string &cmd_name,
107339bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         UNIQUE_VALIDATION_ERROR_CODE error_code) {
10734e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
107355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
107368860b85a52096f9f9b28616bc37feed505497a54Chris Forbes        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
107379bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             error_code, "DS", "Cannot execute command %s on a secondary command buffer. %s", cmd_name.c_str(),
107389bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             validation_error_map[error_code]);
107395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
107405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
107415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
107425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10743bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic void TransitionFinalSubpassLayouts(layer_data *dev_data, GLOBAL_CB_NODE *pCB,
10744bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                          const VkRenderPassBeginInfo *pRenderPassBegin) {
10745127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis    auto renderPass = getRenderPassState(dev_data, pRenderPassBegin->renderPass);
10746cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!renderPass) return;
1074716387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes
10748fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    const VkRenderPassCreateInfo *pRenderPassInfo = renderPass->createInfo.ptr();
10749c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    auto framebuffer = getFramebufferState(dev_data, pRenderPassBegin->framebuffer);
10750cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!framebuffer) return;
10751e3ad4b1284408353cc56a04951c1df1f35a636ceChris Forbes
107525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pRenderPassInfo->attachmentCount; ++i) {
10753628f0e370a17207a87d2632616fc8ca27e7ac80cChris Forbes        auto image_view = framebuffer->createInfo.pAttachments[i];
107545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        SetLayout(dev_data, pCB, image_view, pRenderPassInfo->pAttachments[i].finalLayout);
107555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
107565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
107575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
107588860b85a52096f9f9b28616bc37feed505497a54Chris Forbesstatic bool VerifyRenderAreaBounds(const layer_data *dev_data, const VkRenderPassBeginInfo *pRenderPassBegin) {
10759885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine    bool skip_call = false;
10760c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    const safe_VkFramebufferCreateInfo *pFramebufferInfo =
10761c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis        &getFramebufferState(dev_data, pRenderPassBegin->framebuffer)->createInfo;
10762885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine    if (pRenderPassBegin->renderArea.offset.x < 0 ||
10763885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine        (pRenderPassBegin->renderArea.offset.x + pRenderPassBegin->renderArea.extent.width) > pFramebufferInfo->width ||
10764885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine        pRenderPassBegin->renderArea.offset.y < 0 ||
10765885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine        (pRenderPassBegin->renderArea.offset.y + pRenderPassBegin->renderArea.extent.height) > pFramebufferInfo->height) {
10766885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine        skip_call |= static_cast<bool>(log_msg(
107678860b85a52096f9f9b28616bc37feed505497a54Chris Forbes            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
10768885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            DRAWSTATE_INVALID_RENDER_AREA, "CORE",
10769885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            "Cannot execute a render pass with renderArea not within the bound of the "
10770885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            "framebuffer. RenderArea: x %d, y %d, width %d, height %d. Framebuffer: width %d, "
10771885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            "height %d.",
10772885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            pRenderPassBegin->renderArea.offset.x, pRenderPassBegin->renderArea.offset.y, pRenderPassBegin->renderArea.extent.width,
10773885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            pRenderPassBegin->renderArea.extent.height, pFramebufferInfo->width, pFramebufferInfo->height));
10774885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine    }
10775885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine    return skip_call;
10776885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine}
10777885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine
107781a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski// If this is a stencil format, make sure the stencil[Load|Store]Op flag is checked, while if it is a depth/color attachment the
107791a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski// [load|store]Op flag must be checked
107801a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski// TODO: The memory valid flag in DEVICE_MEM_INFO should probably be split to track the validity of stencil memory separately.
10781cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskitemplate <typename T>
10782cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskistatic bool FormatSpecificLoadAndStoreOpSettings(VkFormat format, T color_depth_op, T stencil_op, T op) {
10783a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski    if (color_depth_op != op && stencil_op != op) {
10784a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski        return false;
10785a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski    }
107861a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski    bool check_color_depth_load_op = !vk_format_is_stencil_only(format);
107871a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski    bool check_stencil_load_op = vk_format_is_depth_and_stencil(format) || !check_color_depth_load_op;
10788a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski
10789a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski    return (((check_color_depth_load_op == true) && (color_depth_op == op)) ||
10790a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski            ((check_stencil_load_op == true) && (stencil_op == op)));
107911a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski}
107921a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski
10793bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
10794bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              VkSubpassContents contents) {
1079583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
107965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
10797b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
10798f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis    GLOBAL_CB_NODE *cb_node = getCBNode(dev_data, commandBuffer);
10799127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis    auto renderPass = pRenderPassBegin ? getRenderPassState(dev_data, pRenderPassBegin->renderPass) : nullptr;
10800c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    auto framebuffer = pRenderPassBegin ? getFramebufferState(dev_data, pRenderPassBegin->framebuffer) : nullptr;
10801f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis    if (cb_node) {
1080216387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes        if (renderPass) {
10803cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            uint32_t clear_op_size = 0;  // Make sure pClearValues is at least as large as last LOAD_OP_CLEAR
10804f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->activeFramebuffer = pRenderPassBegin->framebuffer;
108056e17c244b21ce43ac57404a00a0d844039eed363Mark Lobodzinski            for (uint32_t i = 0; i < renderPass->createInfo.attachmentCount; ++i) {
10806f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes                MT_FB_ATTACHMENT_INFO &fb_info = framebuffer->attachments[i];
10807fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes                auto pAttachment = &renderPass->createInfo.pAttachments[i];
10808bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->loadOp, pAttachment->stencilLoadOp,
108091a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski                                                         VK_ATTACHMENT_LOAD_OP_CLEAR)) {
1081092bc0680357019834b7529148ab6d73353ce02c7Mark Lobodzinski                    clear_op_size = static_cast<uint32_t>(i) + 1;
1081116387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    std::function<bool()> function = [=]() {
108121facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis                        SetImageMemoryValid(dev_data, getImageState(dev_data, fb_info.image), true);
1081316387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                        return false;
1081416387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    };
10815f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                    cb_node->validate_functions.push_back(function);
10816db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes                } else if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->loadOp,
10817bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                pAttachment->stencilLoadOp, VK_ATTACHMENT_LOAD_OP_DONT_CARE)) {
1081816387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    std::function<bool()> function = [=]() {
108191facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis                        SetImageMemoryValid(dev_data, getImageState(dev_data, fb_info.image), false);
1082016387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                        return false;
1082116387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    };
10822f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                    cb_node->validate_functions.push_back(function);
10823db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes                } else if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->loadOp,
10824bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                pAttachment->stencilLoadOp, VK_ATTACHMENT_LOAD_OP_LOAD)) {
1082516387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    std::function<bool()> function = [=]() {
108261facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis                        return ValidateImageMemoryIsValid(dev_data, getImageState(dev_data, fb_info.image),
10827f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis                                                          "vkCmdBeginRenderPass()");
1082816387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    };
10829f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                    cb_node->validate_functions.push_back(function);
1083016387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                }
10831db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes                if (renderPass->attachment_first_read[i]) {
1083216387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    std::function<bool()> function = [=]() {
108331facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis                        return ValidateImageMemoryIsValid(dev_data, getImageState(dev_data, fb_info.image),
10834f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis                                                          "vkCmdBeginRenderPass()");
1083516387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    };
10836f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                    cb_node->validate_functions.push_back(function);
108375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
108385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
108396de3c6ffa0819ee37cd5cecee918b062145e2ff1Tobin Ehlis            if (clear_op_size > pRenderPassBegin->clearValueCount) {
10840369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                skip_call |= log_msg(
10841369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
10842bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    reinterpret_cast<uint64_t &>(renderPass), __LINE__, VALIDATION_ERROR_00442, "DS",
10843bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "In vkCmdBeginRenderPass() the VkRenderPassBeginInfo struct has a clearValueCount of %u but there must "
10844bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "be at least %u entries in pClearValues array to account for the highest index attachment in renderPass "
10845cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "0x%" PRIx64
10846cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    " that uses VK_ATTACHMENT_LOAD_OP_CLEAR is %u. Note that the pClearValues array "
10847bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "is indexed by attachment number so even if some pClearValues entries between 0 and %u correspond to "
10848bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "attachments that aren't cleared they will be ignored. %s",
10849369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                    pRenderPassBegin->clearValueCount, clear_op_size, reinterpret_cast<uint64_t &>(renderPass), clear_op_size,
10850369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                    clear_op_size - 1, validation_error_map[VALIDATION_ERROR_00442]);
10851369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan            }
10852369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan            if (clear_op_size < pRenderPassBegin->clearValueCount) {
10853369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                skip_call |= log_msg(
10854369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                    dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
10855369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                    reinterpret_cast<uint64_t &>(renderPass), __LINE__, DRAWSTATE_RENDERPASS_TOO_MANY_CLEAR_VALUES, "DS",
10856369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                    "In vkCmdBeginRenderPass() the VkRenderPassBeginInfo struct has a clearValueCount of %u but only first %u "
10857369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                    "entries in pClearValues array are used. The highest index attachment in renderPass 0x%" PRIx64
10858369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                    " that uses VK_ATTACHMENT_LOAD_OP_CLEAR is %u - other pClearValues are ignored.",
10859369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                    pRenderPassBegin->clearValueCount, clear_op_size, reinterpret_cast<uint64_t &>(renderPass), clear_op_size);
108603d71bca42a843966040d6ada9c029e0ec9f35ca6Tobin Ehlis            }
1086183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= VerifyRenderAreaBounds(dev_data, pRenderPassBegin);
10862f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            skip_call |= VerifyFramebufferAndRenderPassLayouts(dev_data, cb_node, pRenderPassBegin);
10863ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen            skip_call |= insideRenderPass(dev_data, cb_node, "vkCmdBeginRenderPass()", VALIDATION_ERROR_00440);
1086483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= ValidateDependencies(dev_data, framebuffer, renderPass);
108659bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt            skip_call |= validatePrimaryCommandBuffer(dev_data, cb_node, "vkCmdBeginRenderPass", VALIDATION_ERROR_00441);
1086629f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis            skip_call |= ValidateCmd(dev_data, cb_node, CMD_BEGINRENDERPASS, "vkCmdBeginRenderPass()");
1086729f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis            UpdateCmdBufferLastCmd(dev_data, cb_node, CMD_BEGINRENDERPASS);
10868f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->activeRenderPass = renderPass;
108695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // This is a shallow copy as that is all that is needed for now
10870f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->activeRenderPassBeginInfo = *pRenderPassBegin;
10871f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->activeSubpass = 0;
10872f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->activeSubpassContents = contents;
10873f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->framebuffers.insert(pRenderPassBegin->framebuffer);
10874883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis            // Connect this framebuffer and its children to this cmdBuffer
10875883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis            AddFramebufferBinding(dev_data, cb_node, framebuffer);
10876ea0f86230ff5c52f805ac831a1ed5a92bd123368Chris Forbes            // transition attachments to the correct layouts for the first subpass
10877f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            TransitionSubpassLayouts(dev_data, cb_node, &cb_node->activeRenderPassBeginInfo, cb_node->activeSubpass);
108785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
108795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10880b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
1088183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (!skip_call) {
108824a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdBeginRenderPass(commandBuffer, pRenderPassBegin, contents);
108835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
108845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
108855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1088689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents) {
1088783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
108885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
10889b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
108905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
108915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
108929bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt        skip_call |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdNextSubpass", VALIDATION_ERROR_00459);
1089329f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_NEXTSUBPASS, "vkCmdNextSubpass()");
1089429f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        UpdateCmdBufferLastCmd(dev_data, pCB, CMD_NEXTSUBPASS);
10895ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen        skip_call |= outsideRenderPass(dev_data, pCB, "vkCmdNextSubpass()", VALIDATION_ERROR_00458);
1089680281691386b37385846f21b38e8c9d4b12cc74eChris Forbes
10897fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes        auto subpassCount = pCB->activeRenderPass->createInfo.subpassCount;
1089880281691386b37385846f21b38e8c9d4b12cc74eChris Forbes        if (pCB->activeSubpass == subpassCount - 1) {
108999bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt            skip_call |= log_msg(
109009bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
109019bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                reinterpret_cast<uint64_t>(commandBuffer), __LINE__, VALIDATION_ERROR_00453, "DS",
109029bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                "vkCmdNextSubpass(): Attempted to advance beyond final subpass. %s", validation_error_map[VALIDATION_ERROR_00453]);
1090380281691386b37385846f21b38e8c9d4b12cc74eChris Forbes        }
109045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10905b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
1090696ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes
10907cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return;
1090896ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes
109094a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.CmdNextSubpass(commandBuffer, contents);
1091096ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes
1091196ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes    if (pCB) {
10912bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        lock.lock();
10913bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pCB->activeSubpass++;
10914bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pCB->activeSubpassContents = contents;
10915bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        TransitionSubpassLayouts(dev_data, pCB, &pCB->activeRenderPassBeginInfo, pCB->activeSubpass);
1091696ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes    }
109175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
109185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1091989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdEndRenderPass(VkCommandBuffer commandBuffer) {
1092083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
109215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
10922b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
1092358c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes    auto pCB = getCBNode(dev_data, commandBuffer);
1092458c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes    if (pCB) {
10925127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis        RENDER_PASS_STATE *rp_state = pCB->activeRenderPass;
10926c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis        auto framebuffer = getFramebufferState(dev_data, pCB->activeFramebuffer);
10927127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis        if (rp_state) {
10928127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis            if (pCB->activeSubpass != rp_state->createInfo.subpassCount - 1) {
109299bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                skip_call |= log_msg(
109309bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
109319bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                    reinterpret_cast<uint64_t>(commandBuffer), __LINE__, VALIDATION_ERROR_00460, "DS",
109329bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                    "vkCmdEndRenderPass(): Called before reaching final subpass. %s", validation_error_map[VALIDATION_ERROR_00460]);
1093302a3382f28fc7c6ec6018165be88aa6fc4f05c9eChris Forbes            }
1093402a3382f28fc7c6ec6018165be88aa6fc4f05c9eChris Forbes
10935127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis            for (size_t i = 0; i < rp_state->createInfo.attachmentCount; ++i) {
10936e3ad4b1284408353cc56a04951c1df1f35a636ceChris Forbes                MT_FB_ATTACHMENT_INFO &fb_info = framebuffer->attachments[i];
10937127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                auto pAttachment = &rp_state->createInfo.pAttachments[i];
10938bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->storeOp, pAttachment->stencilStoreOp,
10939bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                         VK_ATTACHMENT_STORE_OP_STORE)) {
1094058c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    std::function<bool()> function = [=]() {
109411facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis                        SetImageMemoryValid(dev_data, getImageState(dev_data, fb_info.image), true);
1094258c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                        return false;
1094358c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    };
1094458c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    pCB->validate_functions.push_back(function);
10945db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes                } else if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->storeOp,
10946bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                pAttachment->stencilStoreOp, VK_ATTACHMENT_STORE_OP_DONT_CARE)) {
1094758c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    std::function<bool()> function = [=]() {
109481facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis                        SetImageMemoryValid(dev_data, getImageState(dev_data, fb_info.image), false);
1094958c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                        return false;
1095058c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    };
1095158c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    pCB->validate_functions.push_back(function);
109525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
109535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
109545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
10955ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen        skip_call |= outsideRenderPass(dev_data, pCB, "vkCmdEndRenderpass()", VALIDATION_ERROR_00464);
109569bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt        skip_call |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdEndRenderPass", VALIDATION_ERROR_00465);
1095729f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_ENDRENDERPASS, "vkCmdEndRenderPass()");
1095829f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        UpdateCmdBufferLastCmd(dev_data, pCB, CMD_ENDRENDERPASS);
109590e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes    }
109600e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes    lock.unlock();
109610e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes
10962cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return;
109630e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes
109644a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.CmdEndRenderPass(commandBuffer);
109650e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes
109660e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes    if (pCB) {
109670e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes        lock.lock();
10968f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes        TransitionFinalSubpassLayouts(dev_data, pCB, &pCB->activeRenderPassBeginInfo);
1096958c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes        pCB->activeRenderPass = nullptr;
1097058c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes        pCB->activeSubpass = 0;
1097158c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes        pCB->activeFramebuffer = VK_NULL_HANDLE;
109725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
109735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
109745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10975a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlisstatic bool logInvalidAttachmentMessage(layer_data *dev_data, VkCommandBuffer secondaryBuffer, uint32_t primaryAttach,
10976a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                        uint32_t secondaryAttach, const char *msg) {
109775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
10978cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                   VALIDATION_ERROR_02059, "DS", "vkCmdExecuteCommands() called w/ invalid Secondary Cmd Buffer 0x%" PRIx64
10979cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                 " which has a render pass "
10980cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                 "that is not compatible with the Primary Cmd Buffer current render pass. "
10981cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                 "Attachment %u is not compatible with %u: %s. %s",
109829bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                   reinterpret_cast<uint64_t &>(secondaryBuffer), primaryAttach, secondaryAttach, msg,
109839bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                   validation_error_map[VALIDATION_ERROR_02059]);
109845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
109855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10986a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlisstatic bool validateAttachmentCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer,
10987a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                            VkRenderPassCreateInfo const *primaryPassCI, uint32_t primaryAttach,
10988a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                            VkCommandBuffer secondaryBuffer, VkRenderPassCreateInfo const *secondaryPassCI,
10989e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                                            uint32_t secondaryAttach, bool is_multi) {
109905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool skip_call = false;
10991a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (primaryPassCI->attachmentCount <= primaryAttach) {
109925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        primaryAttach = VK_ATTACHMENT_UNUSED;
109935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10994a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (secondaryPassCI->attachmentCount <= secondaryAttach) {
109955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        secondaryAttach = VK_ATTACHMENT_UNUSED;
109965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
109975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (primaryAttach == VK_ATTACHMENT_UNUSED && secondaryAttach == VK_ATTACHMENT_UNUSED) {
109985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return skip_call;
109995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
110005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (primaryAttach == VK_ATTACHMENT_UNUSED) {
11001a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach,
11002a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                                 "The first is unused while the second is not.");
110035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return skip_call;
110045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
110055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (secondaryAttach == VK_ATTACHMENT_UNUSED) {
11006a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach,
11007a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                                 "The second is unused while the first is not.");
110085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return skip_call;
110095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
11010a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (primaryPassCI->pAttachments[primaryAttach].format != secondaryPassCI->pAttachments[secondaryAttach].format) {
11011a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        skip_call |=
11012a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis            logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach, "They have different formats.");
110135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
11014a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (primaryPassCI->pAttachments[primaryAttach].samples != secondaryPassCI->pAttachments[secondaryAttach].samples) {
11015a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        skip_call |=
11016a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis            logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach, "They have different samples.");
110175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
11018a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (is_multi && primaryPassCI->pAttachments[primaryAttach].flags != secondaryPassCI->pAttachments[secondaryAttach].flags) {
11019a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        skip_call |=
11020a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis            logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach, "They have different flags.");
110215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
110225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
110235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
110245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11025a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlisstatic bool validateSubpassCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer,
11026a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                         VkRenderPassCreateInfo const *primaryPassCI, VkCommandBuffer secondaryBuffer,
11027a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                         VkRenderPassCreateInfo const *secondaryPassCI, const int subpass, bool is_multi) {
110285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool skip_call = false;
11029a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    const VkSubpassDescription &primary_desc = primaryPassCI->pSubpasses[subpass];
11030a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    const VkSubpassDescription &secondary_desc = secondaryPassCI->pSubpasses[subpass];
110315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t maxInputAttachmentCount = std::max(primary_desc.inputAttachmentCount, secondary_desc.inputAttachmentCount);
110325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < maxInputAttachmentCount; ++i) {
110335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primary_input_attach = VK_ATTACHMENT_UNUSED, secondary_input_attach = VK_ATTACHMENT_UNUSED;
110345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < primary_desc.inputAttachmentCount) {
110355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            primary_input_attach = primary_desc.pInputAttachments[i].attachment;
110365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
110375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < secondary_desc.inputAttachmentCount) {
110385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            secondary_input_attach = secondary_desc.pInputAttachments[i].attachment;
110395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
11040a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPassCI, primary_input_attach, secondaryBuffer,
11041a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                                     secondaryPassCI, secondary_input_attach, is_multi);
110425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
110435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t maxColorAttachmentCount = std::max(primary_desc.colorAttachmentCount, secondary_desc.colorAttachmentCount);
110445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < maxColorAttachmentCount; ++i) {
110455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primary_color_attach = VK_ATTACHMENT_UNUSED, secondary_color_attach = VK_ATTACHMENT_UNUSED;
110465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < primary_desc.colorAttachmentCount) {
110475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            primary_color_attach = primary_desc.pColorAttachments[i].attachment;
110485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
110495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < secondary_desc.colorAttachmentCount) {
110505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            secondary_color_attach = secondary_desc.pColorAttachments[i].attachment;
110515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
11052a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPassCI, primary_color_attach, secondaryBuffer,
11053a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                                     secondaryPassCI, secondary_color_attach, is_multi);
110545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primary_resolve_attach = VK_ATTACHMENT_UNUSED, secondary_resolve_attach = VK_ATTACHMENT_UNUSED;
110555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < primary_desc.colorAttachmentCount && primary_desc.pResolveAttachments) {
110565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            primary_resolve_attach = primary_desc.pResolveAttachments[i].attachment;
110575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
110585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < secondary_desc.colorAttachmentCount && secondary_desc.pResolveAttachments) {
110595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            secondary_resolve_attach = secondary_desc.pResolveAttachments[i].attachment;
110605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
11061a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPassCI, primary_resolve_attach,
11062a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                                     secondaryBuffer, secondaryPassCI, secondary_resolve_attach, is_multi);
110635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
110645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t primary_depthstencil_attach = VK_ATTACHMENT_UNUSED, secondary_depthstencil_attach = VK_ATTACHMENT_UNUSED;
110655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (primary_desc.pDepthStencilAttachment) {
110665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        primary_depthstencil_attach = primary_desc.pDepthStencilAttachment[0].attachment;
110675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
110685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (secondary_desc.pDepthStencilAttachment) {
110695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        secondary_depthstencil_attach = secondary_desc.pDepthStencilAttachment[0].attachment;
110705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
11071a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPassCI, primary_depthstencil_attach,
11072a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                                 secondaryBuffer, secondaryPassCI, secondary_depthstencil_attach, is_multi);
110735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
110745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
110755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11076a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis// Verify that given renderPass CreateInfo for primary and secondary command buffers are compatible.
11077a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis//  This function deals directly with the CreateInfo, there are overloaded versions below that can take the renderPass handle and
11078a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis//  will then feed into this function
11079a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlisstatic bool validateRenderPassCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer,
11080a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                            VkRenderPassCreateInfo const *primaryPassCI, VkCommandBuffer secondaryBuffer,
11081a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                            VkRenderPassCreateInfo const *secondaryPassCI) {
110825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool skip_call = false;
11083a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis
11084a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (primaryPassCI->subpassCount != secondaryPassCI->subpassCount) {
110855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
110865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                             DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
11087a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                             "vkCmdExecuteCommands() called w/ invalid secondary Cmd Buffer 0x%" PRIx64
11088a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                             " that has a subpassCount of %u that is incompatible with the primary Cmd Buffer 0x%" PRIx64
11089a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                             " that has a subpassCount of %u.",
11090a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                             reinterpret_cast<uint64_t &>(secondaryBuffer), secondaryPassCI->subpassCount,
11091a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                             reinterpret_cast<uint64_t &>(primaryBuffer), primaryPassCI->subpassCount);
11092a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    } else {
11093a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        for (uint32_t i = 0; i < primaryPassCI->subpassCount; ++i) {
11094a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis            skip_call |= validateSubpassCompatibility(dev_data, primaryBuffer, primaryPassCI, secondaryBuffer, secondaryPassCI, i,
11095a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                                      primaryPassCI->subpassCount > 1);
11096a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        }
110975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
110985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
110995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
111005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11101e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool validateFramebuffer(layer_data *dev_data, VkCommandBuffer primaryBuffer, const GLOBAL_CB_NODE *pCB,
11102e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                                VkCommandBuffer secondaryBuffer, const GLOBAL_CB_NODE *pSubCB) {
111035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool skip_call = false;
111045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (!pSubCB->beginInfo.pInheritanceInfo) {
111055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return skip_call;
111065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
11107c5b97dda856ff837638b3ebb7e231d5507c495a3Chris Forbes    VkFramebuffer primary_fb = pCB->activeFramebuffer;
111085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkFramebuffer secondary_fb = pSubCB->beginInfo.pInheritanceInfo->framebuffer;
111095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (secondary_fb != VK_NULL_HANDLE) {
111105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (primary_fb != secondary_fb) {
111119bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt            skip_call |= log_msg(
111129bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
111139bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                VALIDATION_ERROR_02060, "DS",
111149bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                "vkCmdExecuteCommands() called w/ invalid secondary command buffer 0x%" PRIx64 " which has a framebuffer 0x%" PRIx64
111159bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                " that is not the same as the primary command buffer's current active framebuffer 0x%" PRIx64 ". %s",
111169bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                reinterpret_cast<uint64_t &>(secondaryBuffer), reinterpret_cast<uint64_t &>(secondary_fb),
111179bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                reinterpret_cast<uint64_t &>(primary_fb), validation_error_map[VALIDATION_ERROR_02060]);
111185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
11119c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis        auto fb = getFramebufferState(dev_data, secondary_fb);
11120e3ad4b1284408353cc56a04951c1df1f35a636ceChris Forbes        if (!fb) {
11121bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
11122bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
11123bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 "vkCmdExecuteCommands() called w/ invalid Cmd Buffer 0x%p "
11124bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 "which has invalid framebuffer 0x%" PRIx64 ".",
11125bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 (void *)secondaryBuffer, (uint64_t)(secondary_fb));
111265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return skip_call;
111275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
11128127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis        auto cb_renderpass = getRenderPassState(dev_data, pSubCB->beginInfo.pInheritanceInfo->renderPass);
11129a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        if (cb_renderpass->renderPass != fb->createInfo.renderPass) {
11130a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis            skip_call |= validateRenderPassCompatibility(dev_data, secondaryBuffer, fb->renderPassCreateInfo.ptr(), secondaryBuffer,
11131fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes                                                         cb_renderpass->createInfo.ptr());
11132a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        }
111335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
111345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
111355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
111365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11137e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool validateSecondaryCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB, GLOBAL_CB_NODE *pSubCB) {
1113883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
111395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_set<int> activeTypes;
111405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto queryObject : pCB->activeQueries) {
111415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto queryPoolData = dev_data->queryPoolMap.find(queryObject.pool);
111425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (queryPoolData != dev_data->queryPoolMap.end()) {
111435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (queryPoolData->second.createInfo.queryType == VK_QUERY_TYPE_PIPELINE_STATISTICS &&
111445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pSubCB->beginInfo.pInheritanceInfo) {
111455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                VkQueryPipelineStatisticFlags cmdBufStatistics = pSubCB->beginInfo.pInheritanceInfo->pipelineStatistics;
111465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if ((cmdBufStatistics & queryPoolData->second.createInfo.pipelineStatistics) != cmdBufStatistics) {
11147cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
11148cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         __LINE__, VALIDATION_ERROR_02065, "DS",
11149cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         "vkCmdExecuteCommands() called w/ invalid Cmd Buffer 0x%p "
11150cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         "which has invalid active query pool 0x%" PRIx64
11151cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         ". Pipeline statistics is being queried so the command "
11152cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         "buffer must have all bits set on the queryPool. %s",
11153cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         pCB->commandBuffer, reinterpret_cast<const uint64_t &>(queryPoolData->first),
11154cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         validation_error_map[VALIDATION_ERROR_02065]);
111555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
111565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
111575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            activeTypes.insert(queryPoolData->second.createInfo.queryType);
111585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
111595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
111605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto queryObject : pSubCB->startedQueries) {
111615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto queryPoolData = dev_data->queryPoolMap.find(queryObject.pool);
111625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (queryPoolData != dev_data->queryPoolMap.end() && activeTypes.count(queryPoolData->second.createInfo.queryType)) {
11163cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
11164cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
11165cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "vkCmdExecuteCommands() called w/ invalid Cmd Buffer 0x%p "
11166cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "which has invalid active query pool 0x%" PRIx64
11167cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "of type %d but a query of that type has been started on "
11168cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "secondary Cmd Buffer 0x%p.",
11169cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 pCB->commandBuffer, reinterpret_cast<const uint64_t &>(queryPoolData->first),
11170cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 queryPoolData->second.createInfo.queryType, pSubCB->commandBuffer);
111715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
111725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
111737bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
111747bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski    auto primary_pool = getCommandPoolNode(dev_data, pCB->createInfo.commandPool);
111757bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski    auto secondary_pool = getCommandPoolNode(dev_data, pSubCB->createInfo.commandPool);
111767bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski    if (primary_pool && secondary_pool && (primary_pool->queueFamilyIndex != secondary_pool->queueFamilyIndex)) {
11177226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis        skip_call |=
11178226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
11179226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    reinterpret_cast<uint64_t>(pSubCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_QUEUE_FAMILY, "DS",
11180226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    "vkCmdExecuteCommands(): Primary command buffer 0x%p"
11181226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    " created in queue family %d has secondary command buffer 0x%p created in queue family %d.",
11182226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    pCB->commandBuffer, primary_pool->queueFamilyIndex, pSubCB->commandBuffer, secondary_pool->queueFamilyIndex);
111837bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski    }
111847bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
1118583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
111865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
111875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11188bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBuffersCount,
11189bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              const VkCommandBuffer *pCommandBuffers) {
1119083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
111915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
11192b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
111935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
111945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
111955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        GLOBAL_CB_NODE *pSubCB = NULL;
111965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < commandBuffersCount; i++) {
111975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pSubCB = getCBNode(dev_data, pCommandBuffers[i]);
111980a8b955c23012196339f3c10ffedc631ea0f7c58Tobin Ehlis            assert(pSubCB);
111990a8b955c23012196339f3c10ffedc631ea0f7c58Tobin Ehlis            if (VK_COMMAND_BUFFER_LEVEL_PRIMARY == pSubCB->createInfo.level) {
1120083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
112014b6738a6adb4e813d66234defee5d18b7c84340dMike Weiblen                                     __LINE__, VALIDATION_ERROR_00153, "DS",
1120283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                     "vkCmdExecuteCommands() called w/ Primary Cmd Buffer 0x%p in element %u of pCommandBuffers "
112034b6738a6adb4e813d66234defee5d18b7c84340dMike Weiblen                                     "array. All cmd buffers in pCommandBuffers array must be secondary. %s",
11204226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                     pCommandBuffers[i], i, validation_error_map[VALIDATION_ERROR_00153]);
11205cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else if (pCB->activeRenderPass) {  // Secondary CB w/i RenderPass must have *CONTINUE_BIT set
11206127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                auto secondary_rp_state = getRenderPassState(dev_data, pSubCB->beginInfo.pInheritanceInfo->renderPass);
112075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (!(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
1120883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |= log_msg(
112095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
112104b6738a6adb4e813d66234defee5d18b7c84340dMike Weiblen                        (uint64_t)pCommandBuffers[i], __LINE__, VALIDATION_ERROR_02057, "DS",
11211414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                        "vkCmdExecuteCommands(): Secondary Command Buffer (0x%p) executed within render pass (0x%" PRIxLEAST64
112124b6738a6adb4e813d66234defee5d18b7c84340dMike Weiblen                        ") must have had vkBeginCommandBuffer() called w/ VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT set. %s",
11213226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        pCommandBuffers[i], (uint64_t)pCB->activeRenderPass->renderPass,
112144b6738a6adb4e813d66234defee5d18b7c84340dMike Weiblen                        validation_error_map[VALIDATION_ERROR_02057]);
112155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                } else {
112165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    // Make sure render pass is compatible with parent command buffer pass if has continue
11217127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                    if (pCB->activeRenderPass->renderPass != secondary_rp_state->renderPass) {
11218fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes                        skip_call |=
11219fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes                            validateRenderPassCompatibility(dev_data, commandBuffer, pCB->activeRenderPass->createInfo.ptr(),
11220127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                                                            pCommandBuffers[i], secondary_rp_state->createInfo.ptr());
11221a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                    }
112221af6125615cd6dd9735d32e2ee8684abeff28d41Tobin Ehlis                    //  If framebuffer for secondary CB is not NULL, then it must match active FB from primaryCB
1122383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |= validateFramebuffer(dev_data, commandBuffer, pCB, pCommandBuffers[i], pSubCB);
112245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
112255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                string errorString = "";
112261af6125615cd6dd9735d32e2ee8684abeff28d41Tobin Ehlis                // secondaryCB must have been created w/ RP compatible w/ primaryCB active renderpass
11227127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                if ((pCB->activeRenderPass->renderPass != secondary_rp_state->renderPass) &&
11228fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes                    !verify_renderpass_compatibility(dev_data, pCB->activeRenderPass->createInfo.ptr(),
11229127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                                                     secondary_rp_state->createInfo.ptr(), errorString)) {
1123083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |= log_msg(
112315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
112325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        (uint64_t)pCommandBuffers[i], __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE, "DS",
11233414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                        "vkCmdExecuteCommands(): Secondary Command Buffer (0x%p) w/ render pass (0x%" PRIxLEAST64
11234414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                        ") is incompatible w/ primary command buffer (0x%p) w/ render pass (0x%" PRIxLEAST64 ") due to: %s",
11235226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        pCommandBuffers[i], (uint64_t)pSubCB->beginInfo.pInheritanceInfo->renderPass, commandBuffer,
11236ee691f5c5fa87aac3750454d2bca2cb582e4e817Chris Forbes                        (uint64_t)pCB->activeRenderPass->renderPass, errorString.c_str());
112375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
112385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
112395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // TODO(mlentine): Move more logic into this method
1124083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= validateSecondaryCommandBufferState(dev_data, pCB, pSubCB);
1124175b0d6603382dcb3e3de24c11ea6e4aa2ef8b4d2Tobin Ehlis            skip_call |= validateCommandBufferState(dev_data, pSubCB, "vkCmdExecuteCommands()");
112425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Secondary cmdBuffers are considered pending execution starting w/
112435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // being recorded
112445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
112455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (dev_data->globalInFlightCmdBuffers.find(pSubCB->commandBuffer) != dev_data->globalInFlightCmdBuffers.end()) {
11246cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
11247cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)(pCB->commandBuffer), __LINE__,
11248cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         VALIDATION_ERROR_00154, "DS",
11249cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         "Attempt to simultaneously execute command buffer 0x%p"
11250cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         " without VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set! %s",
11251cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         pCB->commandBuffer, validation_error_map[VALIDATION_ERROR_00154]);
112525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
112535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT) {
112545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    // Warn that non-simultaneous secondary cmd buffer renders primary non-simultaneous
1125583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |= log_msg(
112565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
112575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        (uint64_t)(pCommandBuffers[i]), __LINE__, DRAWSTATE_INVALID_CB_SIMULTANEOUS_USE, "DS",
11258226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "vkCmdExecuteCommands(): Secondary Command Buffer (0x%p) "
11259226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set and will cause primary command buffer "
11260226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "(0x%p) to be treated as if it does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT "
1126183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                        "set, even though it does.",
11262226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        pCommandBuffers[i], pCB->commandBuffer);
112635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    pCB->beginInfo.flags &= ~VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
112645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
112655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
11266f71dd305f197826a61f398bff725267a20ea1d90Chris Forbes            if (!pCB->activeQueries.empty() && !dev_data->enabled_features.inheritedQueries) {
11267cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                skip_call |=
11268cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
11269cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            reinterpret_cast<uint64_t>(pCommandBuffers[i]), __LINE__, VALIDATION_ERROR_02062, "DS",
11270cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "vkCmdExecuteCommands(): Secondary Command Buffer "
11271cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "(0x%p) cannot be submitted with a query in "
11272cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "flight and inherited queries not "
11273cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "supported on this device. %s",
11274cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            pCommandBuffers[i], validation_error_map[VALIDATION_ERROR_02062]);
112755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
112768567fecbf563420f5900ade277ca68908aa87259Tobin Ehlis            // Propagate layout transitions to the primary cmd buffer
112778567fecbf563420f5900ade277ca68908aa87259Tobin Ehlis            for (auto ilm_entry : pSubCB->imageLayoutMap) {
112788567fecbf563420f5900ade277ca68908aa87259Tobin Ehlis                SetLayout(pCB, ilm_entry.first, ilm_entry.second);
112798567fecbf563420f5900ade277ca68908aa87259Tobin Ehlis            }
112805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pSubCB->primaryCommandBuffer = pCB->commandBuffer;
112815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pCB->secondaryCommandBuffers.insert(pSubCB->commandBuffer);
112825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->globalInFlightCmdBuffers.insert(pSubCB->commandBuffer);
11283d4ee9fdb2def1e9dc70c5627c9103e264471b8ebMichael Lentine            for (auto &function : pSubCB->queryUpdates) {
11284d4ee9fdb2def1e9dc70c5627c9103e264471b8ebMichael Lentine                pCB->queryUpdates.push_back(function);
11285d4ee9fdb2def1e9dc70c5627c9103e264471b8ebMichael Lentine            }
112865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
112879bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt        skip_call |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdExecuteComands", VALIDATION_ERROR_00163);
1128829f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_EXECUTECOMMANDS, "vkCmdExecuteComands()");
1128929f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        UpdateCmdBufferLastCmd(dev_data, pCB, CMD_EXECUTECOMMANDS);
112905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
11291b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
11292cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdExecuteCommands(commandBuffer, commandBuffersCount, pCommandBuffers);
112935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
112945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11295b05be7c81dfbaef10cf00e2cc1c3832026fde765Tobin Ehlis// For any image objects that overlap mapped memory, verify that their layouts are PREINIT or GENERAL
11296cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlisstatic bool ValidateMapImageLayouts(VkDevice device, DEVICE_MEM_INFO const *mem_info, VkDeviceSize offset,
11297623548a271287ae55415e45e3c654ee66d4e79ffTobin Ehlis                                    VkDeviceSize end_offset) {
11298e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
112995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
11300cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    // Iterate over all bound image ranges and verify that for any that overlap the
11301cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    //  map ranges, the layouts are VK_IMAGE_LAYOUT_PREINITIALIZED or VK_IMAGE_LAYOUT_GENERAL
11302cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    // TODO : This can be optimized if we store ranges based on starting address and early exit when we pass our range
11303cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    for (auto image_handle : mem_info->bound_images) {
11304cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis        auto img_it = mem_info->bound_ranges.find(image_handle);
11305cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis        if (img_it != mem_info->bound_ranges.end()) {
11306623548a271287ae55415e45e3c654ee66d4e79ffTobin Ehlis            if (rangesIntersect(dev_data, &img_it->second, offset, end_offset)) {
11307b05be7c81dfbaef10cf00e2cc1c3832026fde765Tobin Ehlis                std::vector<VkImageLayout> layouts;
11308825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis                if (FindLayouts(dev_data, VkImage(image_handle), layouts)) {
11309b05be7c81dfbaef10cf00e2cc1c3832026fde765Tobin Ehlis                    for (auto layout : layouts) {
11310b05be7c81dfbaef10cf00e2cc1c3832026fde765Tobin Ehlis                        if (layout != VK_IMAGE_LAYOUT_PREINITIALIZED && layout != VK_IMAGE_LAYOUT_GENERAL) {
11311cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
11312cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                 (VkDebugReportObjectTypeEXT)0, 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
11313cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                 "Cannot map an image with layout %s. Only "
11314cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                 "GENERAL or PREINITIALIZED are supported.",
11315cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                 string_VkImageLayout(layout));
11316b05be7c81dfbaef10cf00e2cc1c3832026fde765Tobin Ehlis                        }
11317b05be7c81dfbaef10cf00e2cc1c3832026fde765Tobin Ehlis                    }
11318b05be7c81dfbaef10cf00e2cc1c3832026fde765Tobin Ehlis                }
11319b05be7c81dfbaef10cf00e2cc1c3832026fde765Tobin Ehlis            }
11320b05be7c81dfbaef10cf00e2cc1c3832026fde765Tobin Ehlis        }
113215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
113225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
113235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
113245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11325bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL MapMemory(VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size, VkFlags flags,
11326bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         void **ppData) {
113275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
113285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11329e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
113305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
11331b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
11332cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    DEVICE_MEM_INFO *mem_info = getMemObjInfo(dev_data, mem);
11333cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    if (mem_info) {
11334f541bf53dee6daf82a4c8304354eac599a884d29Tobin Ehlis        // TODO : This could me more fine-grained to track just region that is valid
11335f541bf53dee6daf82a4c8304354eac599a884d29Tobin Ehlis        mem_info->global_valid = true;
11336623548a271287ae55415e45e3c654ee66d4e79ffTobin Ehlis        auto end_offset = (VK_WHOLE_SIZE == size) ? mem_info->alloc_info.allocationSize - 1 : offset + size - 1;
11337623548a271287ae55415e45e3c654ee66d4e79ffTobin Ehlis        skip_call |= ValidateMapImageLayouts(device, mem_info, offset, end_offset);
11338cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis        // TODO : Do we need to create new "bound_range" for the mapped range?
11339623548a271287ae55415e45e3c654ee66d4e79ffTobin Ehlis        SetMemRangesValid(dev_data, mem_info, offset, end_offset);
11340cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis        if ((dev_data->phys_dev_mem_props.memoryTypes[mem_info->alloc_info.memoryTypeIndex].propertyFlags &
11341b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis             VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) {
113422fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen            skip_call = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
113432fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                (uint64_t)mem, __LINE__, VALIDATION_ERROR_00629, "MEM",
113442fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                "Mapping Memory without VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT set: mem obj 0x%" PRIxLEAST64 ". %s",
113452fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                (uint64_t)mem, validation_error_map[VALIDATION_ERROR_00629]);
113465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
113475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
11348f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis    skip_call |= ValidateMapMemRange(dev_data, mem, offset, size);
11349b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
113505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11351e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    if (!skip_call) {
113524a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.MapMemory(device, mem, offset, size, flags, ppData);
113537c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis        if (VK_SUCCESS == result) {
113547c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis            lock.lock();
11355cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis            // TODO : What's the point of this range? See comment on creating new "bound_range" above, which may replace this
113567c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis            storeMemRanges(dev_data, mem, offset, size);
113575f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            initializeAndTrackMemory(dev_data, mem, offset, size, ppData);
113587c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis            lock.unlock();
113597c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis        }
113605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
113615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
113625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
113635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1136489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL UnmapMemory(VkDevice device, VkDeviceMemory mem) {
113658860b85a52096f9f9b28616bc37feed505497a54Chris Forbes    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
1136683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
113675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11368b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
113698860b85a52096f9f9b28616bc37feed505497a54Chris Forbes    skip_call |= deleteMemRanges(dev_data, mem);
11370b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
1137183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (!skip_call) {
113724a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.UnmapMemory(device, mem);
113735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
113745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
113755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
113768860b85a52096f9f9b28616bc37feed505497a54Chris Forbesstatic bool validateMemoryIsMapped(layer_data *dev_data, const char *funcName, uint32_t memRangeCount,
11377e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                                   const VkMappedMemoryRange *pMemRanges) {
11378c7ee6f2fe100c1aacfaa0872832717c906bb8a4aMark Lobodzinski    bool skip = false;
113795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < memRangeCount; ++i) {
113808860b85a52096f9f9b28616bc37feed505497a54Chris Forbes        auto mem_info = getMemObjInfo(dev_data, pMemRanges[i].memory);
1138157fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        if (mem_info) {
11382f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski            if (pMemRanges[i].size == VK_WHOLE_SIZE) {
11383f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                if (mem_info->mem_range.offset > pMemRanges[i].offset) {
11384cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
11385cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)pMemRanges[i].memory, __LINE__,
11386cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    VALIDATION_ERROR_00643, "MEM", "%s: Flush/Invalidate offset (" PRINTF_SIZE_T_SPECIFIER
11387cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                                   ") is less than Memory Object's offset "
11388cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                                   "(" PRINTF_SIZE_T_SPECIFIER "). %s",
11389cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    funcName, static_cast<size_t>(pMemRanges[i].offset),
11390cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    static_cast<size_t>(mem_info->mem_range.offset), validation_error_map[VALIDATION_ERROR_00643]);
11391f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                }
11392f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski            } else {
11393f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                const uint64_t data_end = (mem_info->mem_range.size == VK_WHOLE_SIZE)
11394f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                              ? mem_info->alloc_info.allocationSize
11395f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                              : (mem_info->mem_range.offset + mem_info->mem_range.size);
11396f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                if ((mem_info->mem_range.offset > pMemRanges[i].offset) ||
11397f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                    (data_end < (pMemRanges[i].offset + pMemRanges[i].size))) {
11398c7ee6f2fe100c1aacfaa0872832717c906bb8a4aMark Lobodzinski                    skip |=
11399f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
11400f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                (uint64_t)pMemRanges[i].memory, __LINE__, VALIDATION_ERROR_00642, "MEM",
11401f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                "%s: Flush/Invalidate size or offset (" PRINTF_SIZE_T_SPECIFIER ", " PRINTF_SIZE_T_SPECIFIER
11402f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                ") exceed the Memory Object's upper-bound "
11403f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                "(" PRINTF_SIZE_T_SPECIFIER "). %s",
11404f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                funcName, static_cast<size_t>(pMemRanges[i].offset + pMemRanges[i].size),
11405f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                static_cast<size_t>(pMemRanges[i].offset), static_cast<size_t>(data_end),
11406f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                validation_error_map[VALIDATION_ERROR_00642]);
11407f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                }
114085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
114095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
114105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
11411c7ee6f2fe100c1aacfaa0872832717c906bb8a4aMark Lobodzinski    return skip;
114125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
114135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11414bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinskistatic bool ValidateAndCopyNoncoherentMemoryToDriver(layer_data *dev_data, uint32_t mem_range_count,
11415bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                                     const VkMappedMemoryRange *mem_ranges) {
11416bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski    bool skip = false;
11417bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski    for (uint32_t i = 0; i < mem_range_count; ++i) {
11418bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski        auto mem_info = getMemObjInfo(dev_data, mem_ranges[i].memory);
1141957fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        if (mem_info) {
114205f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            if (mem_info->shadow_copy) {
114215f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                VkDeviceSize size = (mem_info->mem_range.size != VK_WHOLE_SIZE)
114225f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                        ? mem_info->mem_range.size
11423d8a53ade6b5501256798a8b4ec0bc14f72adc1faTobin Ehlis                                        : (mem_info->alloc_info.allocationSize - mem_info->mem_range.offset);
114245f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                char *data = static_cast<char *>(mem_info->shadow_copy);
114255f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                for (uint64_t j = 0; j < mem_info->shadow_pad_size; ++j) {
114265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    if (data[j] != NoncoherentMemoryFillValue) {
11427bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
11428bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                        VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)mem_ranges[i].memory, __LINE__,
11429bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                        MEMTRACK_INVALID_MAP, "MEM", "Memory underflow was detected on mem obj 0x%" PRIxLEAST64,
11430bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                        (uint64_t)mem_ranges[i].memory);
114315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
114325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
114335f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                for (uint64_t j = (size + mem_info->shadow_pad_size); j < (2 * mem_info->shadow_pad_size + size); ++j) {
114345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    if (data[j] != NoncoherentMemoryFillValue) {
11435bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
11436bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                        VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)mem_ranges[i].memory, __LINE__,
11437bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                        MEMTRACK_INVALID_MAP, "MEM", "Memory overflow was detected on mem obj 0x%" PRIxLEAST64,
11438bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                        (uint64_t)mem_ranges[i].memory);
114395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
114405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
114415f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                memcpy(mem_info->p_driver_data, static_cast<void *>(data + mem_info->shadow_pad_size), (size_t)(size));
114425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
114435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
114445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
11445bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski    return skip;
114465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
114475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11448bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinskistatic void CopyNoncoherentMemoryFromDriver(layer_data *dev_data, uint32_t mem_range_count, const VkMappedMemoryRange *mem_ranges) {
11449bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski    for (uint32_t i = 0; i < mem_range_count; ++i) {
114508860b85a52096f9f9b28616bc37feed505497a54Chris Forbes        auto mem_info = getMemObjInfo(dev_data, mem_ranges[i].memory);
114515f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski        if (mem_info && mem_info->shadow_copy) {
114525f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            VkDeviceSize size = (mem_info->mem_range.size != VK_WHOLE_SIZE)
114535f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                    ? mem_info->mem_range.size
114545f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                    : (mem_info->alloc_info.allocationSize - mem_ranges[i].offset);
114555f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            char *data = static_cast<char *>(mem_info->shadow_copy);
114565f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            memcpy(data + mem_info->shadow_pad_size, mem_info->p_driver_data, (size_t)(size));
114579e21e56fc23ade48efd3752d2e2729895eb90349Mark Lobodzinski        }
114589e21e56fc23ade48efd3752d2e2729895eb90349Mark Lobodzinski    }
114599e21e56fc23ade48efd3752d2e2729895eb90349Mark Lobodzinski}
114609e21e56fc23ade48efd3752d2e2729895eb90349Mark Lobodzinski
11461ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinskistatic bool ValidateMappedMemoryRangeDeviceLimits(layer_data *dev_data, const char *func_name, uint32_t mem_range_count,
11462ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                                                  const VkMappedMemoryRange *mem_ranges) {
11463ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski    bool skip = false;
11464ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski    for (uint32_t i = 0; i < mem_range_count; ++i) {
11465ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski        uint64_t atom_size = dev_data->phys_dev_properties.properties.limits.nonCoherentAtomSize;
11466ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski        if (vk_safe_modulo(mem_ranges[i].offset, atom_size) != 0) {
11467ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
11468ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            __LINE__, VALIDATION_ERROR_00644, "MEM",
11469ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            "%s: Offset in pMemRanges[%d] is 0x%" PRIxLEAST64
11470ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            ", which is not a multiple of VkPhysicalDeviceLimits::nonCoherentAtomSize (0x%" PRIxLEAST64 "). %s",
11471ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            func_name, i, mem_ranges[i].offset, atom_size, validation_error_map[VALIDATION_ERROR_00644]);
11472ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski        }
11473ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski        if ((mem_ranges[i].size != VK_WHOLE_SIZE) && (vk_safe_modulo(mem_ranges[i].size, atom_size) != 0)) {
11474ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
11475ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            __LINE__, VALIDATION_ERROR_00645, "MEM",
11476ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            "%s: Size in pMemRanges[%d] is 0x%" PRIxLEAST64
11477ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            ", which is not a multiple of VkPhysicalDeviceLimits::nonCoherentAtomSize (0x%" PRIxLEAST64 "). %s",
11478ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            func_name, i, mem_ranges[i].size, atom_size, validation_error_map[VALIDATION_ERROR_00645]);
11479ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski        }
11480ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski    }
11481ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski    return skip;
11482ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski}
11483ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski
1148480e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinskistatic bool PreCallValidateFlushMappedMemoryRanges(layer_data *dev_data, uint32_t mem_range_count,
1148580e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski                                                   const VkMappedMemoryRange *mem_ranges) {
1148680e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    bool skip = false;
1148780e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    std::lock_guard<std::mutex> lock(global_lock);
1148880e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    skip |= ValidateAndCopyNoncoherentMemoryToDriver(dev_data, mem_range_count, mem_ranges);
1148980e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    skip |= validateMemoryIsMapped(dev_data, "vkFlushMappedMemoryRanges", mem_range_count, mem_ranges);
1149080e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    return skip;
1149180e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski}
1149280e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski
11493bba0de708d942e9a2187158915856995db1c5a4dMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL FlushMappedMemoryRanges(VkDevice device, uint32_t memRangeCount,
11494bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                                       const VkMappedMemoryRange *pMemRanges) {
114955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
114968860b85a52096f9f9b28616bc37feed505497a54Chris Forbes    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
114975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1149880e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    if (!PreCallValidateFlushMappedMemoryRanges(dev_data, memRangeCount, pMemRanges)) {
114994a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.FlushMappedMemoryRanges(device, memRangeCount, pMemRanges);
115005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
115015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
115025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
115035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1150480e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinskistatic bool PreCallValidateInvalidateMappedMemoryRanges(layer_data *dev_data, uint32_t mem_range_count,
1150580e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski                                                        const VkMappedMemoryRange *mem_ranges) {
1150680e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    bool skip = false;
1150780e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    std::lock_guard<std::mutex> lock(global_lock);
1150880e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    skip |= validateMemoryIsMapped(dev_data, "vkInvalidateMappedMemoryRanges", mem_range_count, mem_ranges);
1150980e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    return skip;
1151080e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski}
1151180e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski
1151280e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinskistatic void PostCallRecordInvalidateMappedMemoryRanges(layer_data *dev_data, uint32_t mem_range_count,
1151380e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski                                                       const VkMappedMemoryRange *mem_ranges) {
1151480e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    std::lock_guard<std::mutex> lock(global_lock);
1151580e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    // Update our shadow copy with modified driver data
1151680e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    CopyNoncoherentMemoryFromDriver(dev_data, mem_range_count, mem_ranges);
1151780e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski}
1151880e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski
11519bba0de708d942e9a2187158915856995db1c5a4dMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL InvalidateMappedMemoryRanges(VkDevice device, uint32_t memRangeCount,
11520bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                                            const VkMappedMemoryRange *pMemRanges) {
115215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
115228860b85a52096f9f9b28616bc37feed505497a54Chris Forbes    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
115235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1152480e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    if (!PreCallValidateInvalidateMappedMemoryRanges(dev_data, memRangeCount, pMemRanges)) {
115254a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.InvalidateMappedMemoryRanges(device, memRangeCount, pMemRanges);
1152680e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski        if (result == VK_SUCCESS) {
1152780e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski            PostCallRecordInvalidateMappedMemoryRanges(dev_data, memRangeCount, pMemRanges);
1152880e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski        }
115295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
115305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
115315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
115325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1153389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL BindImageMemory(VkDevice device, VkImage image, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
115345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
115355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
1153683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
11537b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
115381facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    auto image_state = getImageState(dev_data, image);
115391facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (image_state) {
1154094c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis        // Track objects tied to memory
1154147aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski        uint64_t image_handle = reinterpret_cast<uint64_t &>(image);
11542888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis        skip_call = SetMemBinding(dev_data, mem, image_handle, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, "vkBindImageMemory");
11543ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis        if (!image_state->memory_requirements_checked) {
11544ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            // There's not an explicit requirement in the spec to call vkGetImageMemoryRequirements() prior to calling
11545ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            //  BindImageMemory but it's implied in that memory being bound must conform with VkMemoryRequirements from
11546ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            //  vkGetImageMemoryRequirements()
11547ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
11548ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis                                 image_handle, __LINE__, DRAWSTATE_INVALID_IMAGE, "DS",
1154903359bff798ddbf27e682a824b0b757f87e78df4Mark Lobodzinski                                 "vkBindImageMemory(): Binding memory to image 0x%" PRIxLEAST64
11550ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis                                 " but vkGetImageMemoryRequirements() has not been called on that image.",
11551ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis                                 image_handle);
11552ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            // Make the call for them so we can verify the state
11553ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            lock.unlock();
11554ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            dev_data->dispatch_table.GetImageMemoryRequirements(device, image, &image_state->requirements);
11555ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            lock.lock();
11556ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis        }
1155747aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
1155847aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski        // Track and validate bound memory range information
1155957fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        auto mem_info = getMemObjInfo(dev_data, mem);
1156057fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        if (mem_info) {
11561ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            skip_call |= InsertImageMemoryRange(dev_data, image, mem_info, memoryOffset, image_state->requirements,
115621facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis                                                image_state->createInfo.tiling == VK_IMAGE_TILING_LINEAR);
11563f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen            skip_call |= ValidateMemoryTypes(dev_data, mem_info, image_state->requirements.memoryTypeBits, "vkBindImageMemory()",
11564f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                                             VALIDATION_ERROR_00806);
1156547aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski        }
1156647aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
11567b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
1156883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis        if (!skip_call) {
115694a0754042cf090e131e9e769d8a3633c228625beChris Forbes            result = dev_data->dispatch_table.BindImageMemory(device, image, mem, memoryOffset);
11570b9e992386a44404152747d66817a733aa127e281Jeremy Hayes            lock.lock();
11571e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis            image_state->binding.mem = mem;
11572e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis            image_state->binding.offset = memoryOffset;
11573ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            image_state->binding.size = image_state->requirements.size;
11574b9e992386a44404152747d66817a733aa127e281Jeremy Hayes            lock.unlock();
1157594c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis        }
1157694c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis    } else {
1157794c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
1157894c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis                reinterpret_cast<const uint64_t &>(image), __LINE__, MEMTRACK_INVALID_OBJECT, "MT",
11579414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                "vkBindImageMemory: Cannot find invalid image 0x%" PRIx64 ", has it already been deleted?",
1158094c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis                reinterpret_cast<const uint64_t &>(image));
115815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
115825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
115835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
115845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1158589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL SetEvent(VkDevice device, VkEvent event) {
115863ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis    bool skip_call = false;
115873ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
115885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
11589b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
115904710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis    auto event_state = getEventNode(dev_data, event);
115914710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis    if (event_state) {
115924710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        event_state->needsSignaled = false;
115934710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        event_state->stageMask = VK_PIPELINE_STAGE_HOST_BIT;
115944710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        if (event_state->write_in_use) {
115953ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT,
115963ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis                                 reinterpret_cast<const uint64_t &>(event), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
11597414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                                 "Cannot call vkSetEvent() on event 0x%" PRIxLEAST64 " that is already in use by a command buffer.",
115983ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis                                 reinterpret_cast<const uint64_t &>(event));
115993ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis        }
116003ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis    }
11601b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
116026fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    // Host setting event is visible to all queues immediately so update stageMask for any queue that's seen this event
116036fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    // TODO : For correctness this needs separate fix to verify that app doesn't make incorrect assumptions about the
116046fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    // ordering of this command in relation to vkCmd[Set|Reset]Events (see GH297)
116056fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    for (auto queue_data : dev_data->queueMap) {
116066fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis        auto event_entry = queue_data.second.eventToStageMap.find(event);
116076fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis        if (event_entry != queue_data.second.eventToStageMap.end()) {
116086fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis            event_entry->second |= VK_PIPELINE_STAGE_HOST_BIT;
116096fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis        }
116106fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    }
11611cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) result = dev_data->dispatch_table.SetEvent(device, event);
116125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
116135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
116145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11615bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL QueueBindSparse(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo *pBindInfo,
11616bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                               VkFence fence) {
116175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map);
116185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
11619e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
11620b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
11621651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    auto pFence = getFenceNode(dev_data, fence);
1162236c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlis    auto pQueue = getQueueState(dev_data, queue);
11623651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
116244b38d3aa8b6be6a7f5bebb472ab439da0562824fTobin Ehlis    // First verify that fence is not in use
11625651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    skip_call |= ValidateFenceForSubmit(dev_data, pFence);
11626651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
116279867daedbf52debc77d6568162ee21e071699b80Chris Forbes    if (pFence) {
116289867daedbf52debc77d6568162ee21e071699b80Chris Forbes        SubmitFence(pQueue, pFence, bindInfoCount);
116294b38d3aa8b6be6a7f5bebb472ab439da0562824fTobin Ehlis    }
11630651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
116311344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis    for (uint32_t bindIdx = 0; bindIdx < bindInfoCount; ++bindIdx) {
116321344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        const VkBindSparseInfo &bindInfo = pBindInfo[bindIdx];
116335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Track objects tied to memory
116341344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t j = 0; j < bindInfo.bufferBindCount; j++) {
116351344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis            for (uint32_t k = 0; k < bindInfo.pBufferBinds[j].bindCount; k++) {
11636f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                auto sparse_binding = bindInfo.pBufferBinds[j].pBinds[k];
11637f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                if (SetSparseMemBinding(dev_data, {sparse_binding.memory, sparse_binding.memoryOffset, sparse_binding.size},
11638f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                                        (uint64_t)bindInfo.pBufferBinds[j].buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
11639f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                                        "vkQueueBindSparse"))
11640e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                    skip_call = true;
116415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
116425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
116431344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t j = 0; j < bindInfo.imageOpaqueBindCount; j++) {
116441344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis            for (uint32_t k = 0; k < bindInfo.pImageOpaqueBinds[j].bindCount; k++) {
11645f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                auto sparse_binding = bindInfo.pImageOpaqueBinds[j].pBinds[k];
11646f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                if (SetSparseMemBinding(dev_data, {sparse_binding.memory, sparse_binding.memoryOffset, sparse_binding.size},
11647f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                                        (uint64_t)bindInfo.pImageOpaqueBinds[j].image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
11648f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                                        "vkQueueBindSparse"))
11649e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                    skip_call = true;
116505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
116515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
116521344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t j = 0; j < bindInfo.imageBindCount; j++) {
116531344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis            for (uint32_t k = 0; k < bindInfo.pImageBinds[j].bindCount; k++) {
11654f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                auto sparse_binding = bindInfo.pImageBinds[j].pBinds[k];
11655f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                // TODO: This size is broken for non-opaque bindings, need to update to comprehend full sparse binding data
11656f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                VkDeviceSize size = sparse_binding.extent.depth * sparse_binding.extent.height * sparse_binding.extent.width * 4;
11657f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                if (SetSparseMemBinding(dev_data, {sparse_binding.memory, sparse_binding.memoryOffset, size},
11658f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                                        (uint64_t)bindInfo.pImageBinds[j].image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
11659f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                                        "vkQueueBindSparse"))
11660e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                    skip_call = true;
116615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
116625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
116639867daedbf52debc77d6568162ee21e071699b80Chris Forbes
116649867daedbf52debc77d6568162ee21e071699b80Chris Forbes        std::vector<SEMAPHORE_WAIT> semaphore_waits;
116659867daedbf52debc77d6568162ee21e071699b80Chris Forbes        std::vector<VkSemaphore> semaphore_signals;
116661344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t i = 0; i < bindInfo.waitSemaphoreCount; ++i) {
1166701a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            VkSemaphore semaphore = bindInfo.pWaitSemaphores[i];
1166801a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            auto pSemaphore = getSemaphoreNode(dev_data, semaphore);
1166901a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            if (pSemaphore) {
1167001a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes                if (pSemaphore->signaled) {
116719867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    if (pSemaphore->signaler.first != VK_NULL_HANDLE) {
116729867daedbf52debc77d6568162ee21e071699b80Chris Forbes                        semaphore_waits.push_back({semaphore, pSemaphore->signaler.first, pSemaphore->signaler.second});
116739867daedbf52debc77d6568162ee21e071699b80Chris Forbes                        pSemaphore->in_use.fetch_add(1);
116749867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    }
116759867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->signaler.first = VK_NULL_HANDLE;
1167601a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes                    pSemaphore->signaled = false;
116771344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                } else {
11678226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    skip_call |= log_msg(
11679226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
11680226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        reinterpret_cast<const uint64_t &>(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
11681226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "vkQueueBindSparse: Queue 0x%p is waiting on semaphore 0x%" PRIx64 " that has no way to be signaled.",
11682226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        queue, reinterpret_cast<const uint64_t &>(semaphore));
116835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
116845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
116855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
116861344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t i = 0; i < bindInfo.signalSemaphoreCount; ++i) {
1168701a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            VkSemaphore semaphore = bindInfo.pSignalSemaphores[i];
1168801a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            auto pSemaphore = getSemaphoreNode(dev_data, semaphore);
1168901a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            if (pSemaphore) {
1169001a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes                if (pSemaphore->signaled) {
116915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    skip_call =
116925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
116931344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                                reinterpret_cast<const uint64_t &>(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
11694226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                "vkQueueBindSparse: Queue 0x%p is signaling semaphore 0x%" PRIx64
116951344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                                ", but that semaphore is already signaled.",
11696226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                queue, reinterpret_cast<const uint64_t &>(semaphore));
11697bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                } else {
116989867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->signaler.first = queue;
116999867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->signaler.second = pQueue->seq + pQueue->submissions.size() + 1;
117009867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->signaled = true;
117019867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->in_use.fetch_add(1);
117029867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    semaphore_signals.push_back(semaphore);
117039867daedbf52debc77d6568162ee21e071699b80Chris Forbes                }
117045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
117055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
117069867daedbf52debc77d6568162ee21e071699b80Chris Forbes
11707bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pQueue->submissions.emplace_back(std::vector<VkCommandBuffer>(), semaphore_waits, semaphore_signals,
117089867daedbf52debc77d6568162ee21e071699b80Chris Forbes                                         bindIdx == bindInfoCount - 1 ? fence : VK_NULL_HANDLE);
117095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
117109867daedbf52debc77d6568162ee21e071699b80Chris Forbes
117119867daedbf52debc77d6568162ee21e071699b80Chris Forbes    if (pFence && !bindInfoCount) {
117129867daedbf52debc77d6568162ee21e071699b80Chris Forbes        // No work to do, just dropping a fence in the queue by itself.
11713bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pQueue->submissions.emplace_back(std::vector<VkCommandBuffer>(), std::vector<SEMAPHORE_WAIT>(), std::vector<VkSemaphore>(),
117149867daedbf52debc77d6568162ee21e071699b80Chris Forbes                                         fence);
117159867daedbf52debc77d6568162ee21e071699b80Chris Forbes    }
117169867daedbf52debc77d6568162ee21e071699b80Chris Forbes
11717b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
117185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11719cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) return dev_data->dispatch_table.QueueBindSparse(queue, bindInfoCount, pBindInfo, fence);
117205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
117215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
117225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
117235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1172489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateSemaphore(VkDevice device, const VkSemaphoreCreateInfo *pCreateInfo,
1172589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                               const VkAllocationCallbacks *pAllocator, VkSemaphore *pSemaphore) {
117265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
117274a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateSemaphore(device, pCreateInfo, pAllocator, pSemaphore);
117285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
11729b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
11730bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        SEMAPHORE_NODE *sNode = &dev_data->semaphoreMap[*pSemaphore];
117319867daedbf52debc77d6568162ee21e071699b80Chris Forbes        sNode->signaler.first = VK_NULL_HANDLE;
117329867daedbf52debc77d6568162ee21e071699b80Chris Forbes        sNode->signaler.second = 0;
117331344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        sNode->signaled = false;
117345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
117355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
117365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
117375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11738bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateEvent(VkDevice device, const VkEventCreateInfo *pCreateInfo,
11739bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           const VkAllocationCallbacks *pAllocator, VkEvent *pEvent) {
117405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
117414a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateEvent(device, pCreateInfo, pAllocator, pEvent);
117425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
11743b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
117445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->eventMap[*pEvent].needsSignaled = false;
11745293ecfc5e69ed3978a8c04518166d828294870a4Tony Barbour        dev_data->eventMap[*pEvent].write_in_use = 0;
117465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->eventMap[*pEvent].stageMask = VkPipelineStageFlags(0);
117475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
117485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
117495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
117505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
117519ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinskistatic bool PreCallValidateCreateSwapchainKHR(layer_data *dev_data, const char *func_name,
117529ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                                              VkSwapchainCreateInfoKHR const *pCreateInfo, SURFACE_STATE *surface_state,
117539ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                                              SWAPCHAIN_NODE *old_swapchain_state) {
11754d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    auto most_recent_swapchain = surface_state->swapchain ? surface_state->swapchain : surface_state->old_swapchain;
11755d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes
117564bd5f453535de3d3423ff1f9995b4acb15f791d2Chris Forbes    // TODO: revisit this. some of these rules are being relaxed.
11757d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    if (most_recent_swapchain != old_swapchain_state || (surface_state->old_swapchain && surface_state->swapchain)) {
11758d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
11759d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes                    reinterpret_cast<uint64_t>(dev_data->device), __LINE__, DRAWSTATE_SWAPCHAIN_ALREADY_EXISTS, "DS",
117609ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    "%s: surface has an existing swapchain other than oldSwapchain", func_name))
11761d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes            return true;
11762d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    }
11763d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    if (old_swapchain_state && old_swapchain_state->createInfo.surface != pCreateInfo->surface) {
11764d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
11765d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes                    reinterpret_cast<uint64_t const &>(pCreateInfo->oldSwapchain), __LINE__, DRAWSTATE_SWAPCHAIN_WRONG_SURFACE,
117669ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    "DS", "%s: pCreateInfo->oldSwapchain's surface is not pCreateInfo->surface", func_name))
11767d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes            return true;
11768d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    }
117697de258f87ca1192db116a66b209253793d276ebcChris Forbes    auto physical_device_state = getPhysicalDeviceState(dev_data->instance_data, dev_data->physical_device);
117707de258f87ca1192db116a66b209253793d276ebcChris Forbes    if (physical_device_state->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState == UNCALLED) {
117717de258f87ca1192db116a66b209253793d276ebcChris Forbes        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
117727de258f87ca1192db116a66b209253793d276ebcChris Forbes                    reinterpret_cast<uint64_t>(dev_data->physical_device), __LINE__, DRAWSTATE_SWAPCHAIN_CREATE_BEFORE_QUERY, "DS",
117739ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    "%s: surface capabilities not retrieved for this physical device", func_name))
117747de258f87ca1192db116a66b209253793d276ebcChris Forbes            return true;
11775cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    } else {  // have valid capabilities
117765c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        auto &capabilities = physical_device_state->surfaceCapabilities;
117779ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->minImageCount against VkSurfaceCapabilitiesKHR::{min|max}ImageCount:
117782fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen        if (pCreateInfo->minImageCount < capabilities.minImageCount) {
117792fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
117802fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02331, "DS",
117819ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with minImageCount = %d, which is outside the bounds returned "
117822fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        "by vkGetPhysicalDeviceSurfaceCapabilitiesKHR() (i.e. minImageCount = %d, maxImageCount = %d). %s",
117839ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->minImageCount, capabilities.minImageCount, capabilities.maxImageCount,
117842fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        validation_error_map[VALIDATION_ERROR_02331]))
117852fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                return true;
117862fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen        }
117872fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen
117882fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen        if ((capabilities.maxImageCount > 0) && (pCreateInfo->minImageCount > capabilities.maxImageCount)) {
117895c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
117902fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02332, "DS",
117919ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with minImageCount = %d, which is outside the bounds returned "
117922fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        "by vkGetPhysicalDeviceSurfaceCapabilitiesKHR() (i.e. minImageCount = %d, maxImageCount = %d). %s",
117939ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->minImageCount, capabilities.minImageCount, capabilities.maxImageCount,
117942fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        validation_error_map[VALIDATION_ERROR_02332]))
117955c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
117965c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
117972fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen
117989ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->imageExtent against VkSurfaceCapabilitiesKHR::{current|min|max}ImageExtent:
117992e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill        if ((capabilities.currentExtent.width == kSurfaceSizeFromSwapchain) &&
118002e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill            ((pCreateInfo->imageExtent.width < capabilities.minImageExtent.width) ||
118012e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill             (pCreateInfo->imageExtent.width > capabilities.maxImageExtent.width) ||
118022e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill             (pCreateInfo->imageExtent.height < capabilities.minImageExtent.height) ||
118032e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill             (pCreateInfo->imageExtent.height > capabilities.maxImageExtent.height))) {
118045c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
118052fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02334, "DS",
118069ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with imageExtent = (%d,%d), which is outside the bounds returned by "
118079ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "vkGetPhysicalDeviceSurfaceCapabilitiesKHR(): currentExtent = (%d,%d), minImageExtent = (%d,%d), "
118089ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "maxImageExtent = (%d,%d). %s",
118099ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->imageExtent.width, pCreateInfo->imageExtent.height,
118109ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        capabilities.currentExtent.width, capabilities.currentExtent.height, capabilities.minImageExtent.width,
118119ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        capabilities.minImageExtent.height, capabilities.maxImageExtent.width, capabilities.maxImageExtent.height,
118122fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        validation_error_map[VALIDATION_ERROR_02334]))
118135c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
118145c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
118152e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill        if ((capabilities.currentExtent.width != kSurfaceSizeFromSwapchain) &&
118162e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill            ((pCreateInfo->imageExtent.width != capabilities.currentExtent.width) ||
118172e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill             (pCreateInfo->imageExtent.height != capabilities.currentExtent.height))) {
118185c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
118192fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02334, "DS",
118209ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with imageExtent = (%d,%d), which is not equal to the currentExtent = (%d,%d) returned by "
118219ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "vkGetPhysicalDeviceSurfaceCapabilitiesKHR(). %s",
118229ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->imageExtent.width, pCreateInfo->imageExtent.height,
118239ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        capabilities.currentExtent.width, capabilities.currentExtent.height,
118242fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        validation_error_map[VALIDATION_ERROR_02334]))
118255c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
118265c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
118279ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // pCreateInfo->preTransform should have exactly one bit set, and that bit must also be set in
118289ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // VkSurfaceCapabilitiesKHR::supportedTransforms.
118295c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        if (!pCreateInfo->preTransform || (pCreateInfo->preTransform & (pCreateInfo->preTransform - 1)) ||
118305c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            !(pCreateInfo->preTransform & capabilities.supportedTransforms)) {
118319ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            // This is an error situation; one for which we'd like to give the developer a helpful, multi-line error message.  Build
118329ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            // it up a little at a time, and then log it:
118335c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            std::string errorString = "";
118345c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            char str[1024];
118355c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            // Here's the first part of the message:
118369ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            sprintf(str, "%s called with a non-supported pCreateInfo->preTransform (i.e. %s).  Supported values are:\n", func_name,
118375c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    string_VkSurfaceTransformFlagBitsKHR(pCreateInfo->preTransform));
118385c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            errorString += str;
118395c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            for (int i = 0; i < 32; i++) {
118405c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                // Build up the rest of the message:
118415c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                if ((1 << i) & capabilities.supportedTransforms) {
118425c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    const char *newStr = string_VkSurfaceTransformFlagBitsKHR((VkSurfaceTransformFlagBitsKHR)(1 << i));
118435c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    sprintf(str, "    %s\n", newStr);
118445c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    errorString += str;
118455c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                }
118465c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            }
118475c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            // Log the message that we've built up:
118485c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
118492fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t &>(dev_data->device), __LINE__, VALIDATION_ERROR_02339, "DS", "%s. %s",
118502fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        errorString.c_str(), validation_error_map[VALIDATION_ERROR_02339]))
118515c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
118525c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
118537b0d28d116977b91892f354e002edd760bdb86cbChris Forbes
118549ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // pCreateInfo->compositeAlpha should have exactly one bit set, and that bit must also be set in
118559ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // VkSurfaceCapabilitiesKHR::supportedCompositeAlpha
118565c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        if (!pCreateInfo->compositeAlpha || (pCreateInfo->compositeAlpha & (pCreateInfo->compositeAlpha - 1)) ||
118575c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            !((pCreateInfo->compositeAlpha) & capabilities.supportedCompositeAlpha)) {
118589ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            // This is an error situation; one for which we'd like to give the developer a helpful, multi-line error message.  Build
118599ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            // it up a little at a time, and then log it:
118605c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            std::string errorString = "";
118615c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            char str[1024];
118625c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            // Here's the first part of the message:
118639ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            sprintf(str, "%s called with a non-supported pCreateInfo->compositeAlpha (i.e. %s).  Supported values are:\n",
118649ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    func_name, string_VkCompositeAlphaFlagBitsKHR(pCreateInfo->compositeAlpha));
118655c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            errorString += str;
118665c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            for (int i = 0; i < 32; i++) {
118675c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                // Build up the rest of the message:
118685c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                if ((1 << i) & capabilities.supportedCompositeAlpha) {
118695c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    const char *newStr = string_VkCompositeAlphaFlagBitsKHR((VkCompositeAlphaFlagBitsKHR)(1 << i));
118705c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    sprintf(str, "    %s\n", newStr);
118715c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    errorString += str;
118725c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                }
118735c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            }
118745c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            // Log the message that we've built up:
118755c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
118762fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t &>(dev_data->device), __LINE__, VALIDATION_ERROR_02340, "DS", "%s. %s",
118772fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        errorString.c_str(), validation_error_map[VALIDATION_ERROR_02340]))
118785c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
118795c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
118809ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->imageArrayLayers against VkSurfaceCapabilitiesKHR::maxImageArrayLayers:
118815c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        if ((pCreateInfo->imageArrayLayers < 1) || (pCreateInfo->imageArrayLayers > capabilities.maxImageArrayLayers)) {
118825c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
118832fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02335, "DS",
118849ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with a non-supported imageArrayLayers (i.e. %d).  Minimum value is 1, maximum value is %d. %s",
118859ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->imageArrayLayers, capabilities.maxImageArrayLayers,
118862fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        validation_error_map[VALIDATION_ERROR_02335]))
118875c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
118885c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
118899ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->imageUsage against VkSurfaceCapabilitiesKHR::supportedUsageFlags:
118905c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        if (pCreateInfo->imageUsage != (pCreateInfo->imageUsage & capabilities.supportedUsageFlags)) {
118915c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
118922fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02336, "DS",
118939ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with a non-supported pCreateInfo->imageUsage (i.e. 0x%08x).  Supported flag bits are 0x%08x. %s",
118949ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->imageUsage, capabilities.supportedUsageFlags,
118959ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        validation_error_map[VALIDATION_ERROR_02336]))
118965c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
118975c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
118987de258f87ca1192db116a66b209253793d276ebcChris Forbes    }
11899d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes
119009ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski    // Validate pCreateInfo values with the results of vkGetPhysicalDeviceSurfaceFormatsKHR():
119015faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    if (physical_device_state->vkGetPhysicalDeviceSurfaceFormatsKHRState != QUERY_DETAILS) {
119025faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
119035faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    reinterpret_cast<uint64_t>(dev_data->device), __LINE__, DRAWSTATE_SWAPCHAIN_CREATE_BEFORE_QUERY, "DS",
119049ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    "%s called before calling vkGetPhysicalDeviceSurfaceFormatsKHR().", func_name))
119055faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            return true;
119065faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    } else {
119079ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->imageFormat against VkSurfaceFormatKHR::format:
119085faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        bool foundFormat = false;
119095faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        bool foundColorSpace = false;
119105faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        bool foundMatch = false;
119115faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        for (auto const &format : physical_device_state->surface_formats) {
119125faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            if (pCreateInfo->imageFormat == format.format) {
119139ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                // Validate pCreateInfo->imageColorSpace against VkSurfaceFormatKHR::colorSpace:
119145faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                foundFormat = true;
119155faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                if (pCreateInfo->imageColorSpace == format.colorSpace) {
119165faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    foundMatch = true;
119175faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    break;
119185faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                }
119195faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            } else {
119205faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                if (pCreateInfo->imageColorSpace == format.colorSpace) {
119215faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    foundColorSpace = true;
119225faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                }
119235faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            }
119245faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        }
119255faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        if (!foundMatch) {
119265faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            if (!foundFormat) {
119275faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
119282fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                            reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02333, "DS",
11929bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "%s called with a non-supported pCreateInfo->imageFormat (i.e. %d). %s", func_name,
11930bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            pCreateInfo->imageFormat, validation_error_map[VALIDATION_ERROR_02333]))
119312fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                    return true;
119322fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen            }
119332fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen            if (!foundColorSpace) {
119342fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
119352fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                            reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02333, "DS",
11936bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "%s called with a non-supported pCreateInfo->imageColorSpace (i.e. %d). %s", func_name,
11937bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            pCreateInfo->imageColorSpace, validation_error_map[VALIDATION_ERROR_02333]))
119385faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    return true;
119395faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            }
119405faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        }
119415faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    }
119425faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
119439ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski    // Validate pCreateInfo values with the results of vkGetPhysicalDeviceSurfacePresentModesKHR():
119449e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    if (physical_device_state->vkGetPhysicalDeviceSurfacePresentModesKHRState != QUERY_DETAILS) {
1194525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // FIFO is required to always be supported
119469e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        if (pCreateInfo->presentMode != VK_PRESENT_MODE_FIFO_KHR) {
119479e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
119489ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, DRAWSTATE_SWAPCHAIN_CREATE_BEFORE_QUERY, "DS",
119499ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called before calling vkGetPhysicalDeviceSurfacePresentModesKHR().", func_name))
119509e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                return true;
119519e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
119529e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    } else {
119539ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->presentMode against vkGetPhysicalDeviceSurfacePresentModesKHR():
11954bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        bool foundMatch = std::find(physical_device_state->present_modes.begin(), physical_device_state->present_modes.end(),
119559e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                                    pCreateInfo->presentMode) != physical_device_state->present_modes.end();
119569e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        if (!foundMatch) {
119579e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
119582fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02341, "DS",
119599ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with a non-supported presentMode (i.e. %s). %s", func_name,
119602fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        string_VkPresentModeKHR(pCreateInfo->presentMode), validation_error_map[VALIDATION_ERROR_02341]))
119619e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                return true;
119629e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
119639e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    }
119649e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
11965d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    return false;
11966d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes}
11967d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes
11968261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinskistatic void PostCallRecordCreateSwapchainKHR(layer_data *dev_data, VkResult result, const VkSwapchainCreateInfoKHR *pCreateInfo,
11969261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski                                             VkSwapchainKHR *pSwapchain, SURFACE_STATE *surface_state,
11970261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski                                             SWAPCHAIN_NODE *old_swapchain_state) {
119715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
11972b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
11973ddc5201048319558ce66701163a4546ee957af19Chris Forbes        auto swapchain_state = unique_ptr<SWAPCHAIN_NODE>(new SWAPCHAIN_NODE(pCreateInfo, *pSwapchain));
11974ddc5201048319558ce66701163a4546ee957af19Chris Forbes        surface_state->swapchain = swapchain_state.get();
11975ddc5201048319558ce66701163a4546ee957af19Chris Forbes        dev_data->device_extensions.swapchainMap[*pSwapchain] = std::move(swapchain_state);
11976ddc5201048319558ce66701163a4546ee957af19Chris Forbes    } else {
11977ddc5201048319558ce66701163a4546ee957af19Chris Forbes        surface_state->swapchain = nullptr;
119785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
11979ddc5201048319558ce66701163a4546ee957af19Chris Forbes    // Spec requires that even if CreateSwapchainKHR fails, oldSwapchain behaves as replaced.
119805b5488456e5afa0487f95b805a2aba59b13d69f4Chris Forbes    if (old_swapchain_state) {
119815b5488456e5afa0487f95b805a2aba59b13d69f4Chris Forbes        old_swapchain_state->replaced = true;
119825b5488456e5afa0487f95b805a2aba59b13d69f4Chris Forbes    }
11983ddc5201048319558ce66701163a4546ee957af19Chris Forbes    surface_state->old_swapchain = old_swapchain_state;
11984261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski    return;
11985261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski}
11986261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski
11987261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo,
11988261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski                                                  const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchain) {
11989261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
11990261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski    auto surface_state = getSurfaceState(dev_data->instance_data, pCreateInfo->surface);
11991261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski    auto old_swapchain_state = getSwapchainNode(dev_data, pCreateInfo->oldSwapchain);
11992261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski
119939ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski    if (PreCallValidateCreateSwapchainKHR(dev_data, "vkCreateSwapChainKHR()", pCreateInfo, surface_state, old_swapchain_state)) {
11994261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski        return VK_ERROR_VALIDATION_FAILED_EXT;
11995261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski    }
11996261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski
11997261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski    VkResult result = dev_data->dispatch_table.CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain);
11998261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski
11999261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski    PostCallRecordCreateSwapchainKHR(dev_data, result, pCreateInfo, pSwapchain, surface_state, old_swapchain_state);
12000ddc5201048319558ce66701163a4546ee957af19Chris Forbes
120015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
120025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
120035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12004bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks *pAllocator) {
120055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
1200683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
120075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12008b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
12009b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis    auto swapchain_data = getSwapchainNode(dev_data, swapchain);
12010b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis    if (swapchain_data) {
12011b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis        if (swapchain_data->images.size() > 0) {
12012b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis            for (auto swapchain_image : swapchain_data->images) {
120135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                auto image_sub = dev_data->imageSubresourceMap.find(swapchain_image);
120145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (image_sub != dev_data->imageSubresourceMap.end()) {
120155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    for (auto imgsubpair : image_sub->second) {
120165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        auto image_item = dev_data->imageLayoutMap.find(imgsubpair);
120175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        if (image_item != dev_data->imageLayoutMap.end()) {
120185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                            dev_data->imageLayoutMap.erase(image_item);
120195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        }
120205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
120215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    dev_data->imageSubresourceMap.erase(image_sub);
120225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
1202383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                skip_call =
12024f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                    ClearMemoryObjectBindings(dev_data, (uint64_t)swapchain_image, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT);
1202594c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis                dev_data->imageMap.erase(swapchain_image);
120265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
120275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
12028ddc5201048319558ce66701163a4546ee957af19Chris Forbes
12029ddc5201048319558ce66701163a4546ee957af19Chris Forbes        auto surface_state = getSurfaceState(dev_data->instance_data, swapchain_data->createInfo.surface);
12030ddc5201048319558ce66701163a4546ee957af19Chris Forbes        if (surface_state) {
12031cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (surface_state->swapchain == swapchain_data) surface_state->swapchain = nullptr;
12032cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (surface_state->old_swapchain == swapchain_data) surface_state->old_swapchain = nullptr;
12033ddc5201048319558ce66701163a4546ee957af19Chris Forbes        }
12034ddc5201048319558ce66701163a4546ee957af19Chris Forbes
120355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->device_extensions.swapchainMap.erase(swapchain);
120365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
12037b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
12038cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.DestroySwapchainKHR(device, swapchain, pAllocator);
120395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
120405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12041bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pCount,
12042bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                     VkImage *pSwapchainImages) {
120435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
120444a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.GetSwapchainImagesKHR(device, swapchain, pCount, pSwapchainImages);
120455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
120465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS && pSwapchainImages != NULL) {
120475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // This should never happen and is checked by param checker.
12048cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!pCount) return result;
12049b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
120505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const size_t count = *pCount;
12051b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis        auto swapchain_node = getSwapchainNode(dev_data, swapchain);
12052b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis        if (swapchain_node && !swapchain_node->images.empty()) {
120530801763633180d277d26a90343464bd11646056fTobin Ehlis            // TODO : Not sure I like the memcmp here, but it works
120540801763633180d277d26a90343464bd11646056fTobin Ehlis            const bool mismatch = (swapchain_node->images.size() != count ||
120550801763633180d277d26a90343464bd11646056fTobin Ehlis                                   memcmp(&swapchain_node->images[0], pSwapchainImages, sizeof(swapchain_node->images[0]) * count));
120565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (mismatch) {
120575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // TODO: Verify against Valid Usage section of extension
120585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
120595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        (uint64_t)swapchain, __LINE__, MEMTRACK_NONE, "SWAP_CHAIN",
12060414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                        "vkGetSwapchainInfoKHR(0x%" PRIx64
120615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        ", VK_SWAP_CHAIN_INFO_TYPE_PERSISTENT_IMAGES_KHR) returned mismatching data",
120625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        (uint64_t)(swapchain));
120635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
120645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
120655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < *pCount; ++i) {
120665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            IMAGE_LAYOUT_NODE image_layout_node;
120675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            image_layout_node.layout = VK_IMAGE_LAYOUT_UNDEFINED;
120685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            image_layout_node.format = swapchain_node->createInfo.imageFormat;
120696d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            // Add imageMap entries for each swapchain image
120706d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            VkImageCreateInfo image_ci = {};
120716d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.mipLevels = 1;
120726d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.arrayLayers = swapchain_node->createInfo.imageArrayLayers;
120736d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.usage = swapchain_node->createInfo.imageUsage;
120746d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.format = swapchain_node->createInfo.imageFormat;
1207541ebcb6b517b1de5ae456d46d866f5e84a96a2c5Tobin Ehlis            image_ci.samples = VK_SAMPLE_COUNT_1_BIT;
120766d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.extent.width = swapchain_node->createInfo.imageExtent.width;
120776d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.extent.height = swapchain_node->createInfo.imageExtent.height;
120786d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.sharingMode = swapchain_node->createInfo.imageSharingMode;
120791facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            dev_data->imageMap[pSwapchainImages[i]] = unique_ptr<IMAGE_STATE>(new IMAGE_STATE(pSwapchainImages[i], &image_ci));
120801facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            auto &image_state = dev_data->imageMap[pSwapchainImages[i]];
120811facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            image_state->valid = false;
12082e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis            image_state->binding.mem = MEMTRACKER_SWAP_CHAIN_IMAGE_KEY;
120835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            swapchain_node->images.push_back(pSwapchainImages[i]);
120845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            ImageSubresourcePair subpair = {pSwapchainImages[i], false, VkImageSubresource()};
120855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->imageSubresourceMap[pSwapchainImages[i]].push_back(subpair);
120865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->imageLayoutMap[subpair] = image_layout_node;
120875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->device_extensions.imageToSwapchainMap[pSwapchainImages[i]] = swapchain;
120885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
120895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
120905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
120915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
120925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1209389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo) {
120945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map);
120955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool skip_call = false;
120965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
120976c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    std::lock_guard<std::mutex> lock(global_lock);
1209836c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlis    auto queue_state = getQueueState(dev_data, queue);
120991671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes
121006c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    for (uint32_t i = 0; i < pPresentInfo->waitSemaphoreCount; ++i) {
121016c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        auto pSemaphore = getSemaphoreNode(dev_data, pPresentInfo->pWaitSemaphores[i]);
121026c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        if (pSemaphore && !pSemaphore->signaled) {
12103226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
12104226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS,
12105226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                 "DS", "Queue 0x%p is waiting on semaphore 0x%" PRIx64 " that has no way to be signaled.", queue,
12106226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                 reinterpret_cast<const uint64_t &>(pPresentInfo->pWaitSemaphores[i]));
121075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
121086c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    }
12109249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis
121106c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    for (uint32_t i = 0; i < pPresentInfo->swapchainCount; ++i) {
121116c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        auto swapchain_data = getSwapchainNode(dev_data, pPresentInfo->pSwapchains[i]);
12112a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes        if (swapchain_data) {
12113a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes            if (pPresentInfo->pImageIndices[i] >= swapchain_data->images.size()) {
12114bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                skip_call |= log_msg(
12115bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
12116bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    reinterpret_cast<uint64_t const &>(pPresentInfo->pSwapchains[i]), __LINE__, DRAWSTATE_SWAPCHAIN_INVALID_IMAGE,
12117bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "DS", "vkQueuePresentKHR: Swapchain image index too large (%u). There are only %u images in this swapchain.",
12118bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    pPresentInfo->pImageIndices[i], (uint32_t)swapchain_data->images.size());
12119bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            } else {
12120a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                auto image = swapchain_data->images[pPresentInfo->pImageIndices[i]];
121211facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis                auto image_state = getImageState(dev_data, image);
121221facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis                skip_call |= ValidateImageMemoryIsValid(dev_data, image_state, "vkQueuePresentKHR()");
12123a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes
121241facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis                if (!image_state->acquired) {
12125bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    skip_call |= log_msg(
12126bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
12127bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        reinterpret_cast<uint64_t const &>(pPresentInfo->pSwapchains[i]), __LINE__,
12128bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        DRAWSTATE_SWAPCHAIN_IMAGE_NOT_ACQUIRED, "DS",
12129bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        "vkQueuePresentKHR: Swapchain image index %u has not been acquired.", pPresentInfo->pImageIndices[i]);
12130a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                }
12131a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes
12132a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                vector<VkImageLayout> layouts;
12133a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                if (FindLayouts(dev_data, image, layouts)) {
12134a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                    for (auto layout : layouts) {
12135a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                        if (layout != VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) {
12136a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                            skip_call |=
121372fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT,
121382fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                        reinterpret_cast<uint64_t &>(queue), __LINE__, VALIDATION_ERROR_01964, "DS",
121392fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                        "Images passed to present must be in layout "
121402fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                        "VK_IMAGE_LAYOUT_PRESENT_SRC_KHR but is in %s. %s",
121412fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                        string_VkImageLayout(layout), validation_error_map[VALIDATION_ERROR_01964]);
12142a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                        }
121435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
121445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
121455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
121461671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes
121471671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            // All physical devices and queue families are required to be able
121481671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            // to present to any native window on Android; require the
121491671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            // application to have established support on any other platform.
121501671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            if (!dev_data->instance_data->androidSurfaceExtensionEnabled) {
121511671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                auto surface_state = getSurfaceState(dev_data->instance_data, swapchain_data->createInfo.surface);
121521671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                auto support_it = surface_state->gpu_queue_support.find({dev_data->physical_device, queue_state->queueFamilyIndex});
121531671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes
121541671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                if (support_it == surface_state->gpu_queue_support.end()) {
121551671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                    skip_call |=
121561671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
121571671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                                reinterpret_cast<uint64_t const &>(pPresentInfo->pSwapchains[i]), __LINE__,
12158cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                DRAWSTATE_SWAPCHAIN_UNSUPPORTED_QUEUE, "DS",
12159cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                "vkQueuePresentKHR: Presenting image without calling "
12160cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                "vkGetPhysicalDeviceSurfaceSupportKHR");
121611671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                } else if (!support_it->second) {
12162cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip_call |= log_msg(
12163cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
12164cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        reinterpret_cast<uint64_t const &>(pPresentInfo->pSwapchains[i]), __LINE__, VALIDATION_ERROR_01961, "DS",
12165cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "vkQueuePresentKHR: Presenting image on queue that cannot "
12166cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "present to this surface. %s",
12167cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        validation_error_map[VALIDATION_ERROR_01961]);
121681671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                }
121691671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            }
121705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
121715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
121725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
121736c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    if (skip_call) {
121746c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        return VK_ERROR_VALIDATION_FAILED_EXT;
121756c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    }
121766c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes
121774a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.QueuePresentKHR(queue, pPresentInfo);
121786c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes
121796c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    if (result != VK_ERROR_VALIDATION_FAILED_EXT) {
121806c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        // Semaphore waits occur before error generation, if the call reached
121816c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        // the ICD. (Confirm?)
121826c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        for (uint32_t i = 0; i < pPresentInfo->waitSemaphoreCount; ++i) {
121836c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes            auto pSemaphore = getSemaphoreNode(dev_data, pPresentInfo->pWaitSemaphores[i]);
121849867daedbf52debc77d6568162ee21e071699b80Chris Forbes            if (pSemaphore) {
121859867daedbf52debc77d6568162ee21e071699b80Chris Forbes                pSemaphore->signaler.first = VK_NULL_HANDLE;
121866c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes                pSemaphore->signaled = false;
121876c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes            }
121886c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        }
121899867daedbf52debc77d6568162ee21e071699b80Chris Forbes
12190220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes        for (uint32_t i = 0; i < pPresentInfo->swapchainCount; ++i) {
12191220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            // Note: this is imperfect, in that we can get confused about what
12192220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            // did or didn't succeed-- but if the app does that, it's confused
12193220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            // itself just as much.
12194220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            auto local_result = pPresentInfo->pResults ? pPresentInfo->pResults[i] : result;
12195220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes
12196cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (local_result != VK_SUCCESS && local_result != VK_SUBOPTIMAL_KHR) continue;  // this present didn't actually happen.
12197220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes
12198220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            // Mark the image as having been released to the WSI
12199220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            auto swapchain_data = getSwapchainNode(dev_data, pPresentInfo->pSwapchains[i]);
12200220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            auto image = swapchain_data->images[pPresentInfo->pImageIndices[i]];
122011facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            auto image_state = getImageState(dev_data, image);
122021facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            image_state->acquired = false;
12203220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes        }
12204220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes
122059867daedbf52debc77d6568162ee21e071699b80Chris Forbes        // Note: even though presentation is directed to a queue, there is no
122069867daedbf52debc77d6568162ee21e071699b80Chris Forbes        // direct ordering between QP and subsequent work, so QP (and its
122079867daedbf52debc77d6568162ee21e071699b80Chris Forbes        // semaphore waits) /never/ participate in any completion proof.
122086c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    }
122091344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
122105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
122115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
122125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12213c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinskistatic bool PreCallValidateCreateSharedSwapchainsKHR(layer_data *dev_data, uint32_t swapchainCount,
12214c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                     const VkSwapchainCreateInfoKHR *pCreateInfos, VkSwapchainKHR *pSwapchains,
12215c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                     std::vector<SURFACE_STATE *> &surface_state,
12216c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                     std::vector<SWAPCHAIN_NODE *> &old_swapchain_state) {
122170342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    if (pCreateInfos) {
12218c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski        std::lock_guard<std::mutex> lock(global_lock);
122190342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        for (uint32_t i = 0; i < swapchainCount; i++) {
122200342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            surface_state.push_back(getSurfaceState(dev_data->instance_data, pCreateInfos[i].surface));
122210342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            old_swapchain_state.push_back(getSwapchainNode(dev_data, pCreateInfos[i].oldSwapchain));
122229ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            std::stringstream func_name;
122239ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            func_name << "vkCreateSharedSwapchainsKHR[" << swapchainCount << "]";
12224bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (PreCallValidateCreateSwapchainKHR(dev_data, func_name.str().c_str(), &pCreateInfos[i], surface_state[i],
12225bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                  old_swapchain_state[i])) {
12226c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                return true;
122270342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            }
122280342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        }
122290342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    }
12230c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    return false;
12231c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski}
122320342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski
12233c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinskistatic void PostCallRecordCreateSharedSwapchainsKHR(layer_data *dev_data, VkResult result, uint32_t swapchainCount,
12234c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                    const VkSwapchainCreateInfoKHR *pCreateInfos, VkSwapchainKHR *pSwapchains,
12235c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                    std::vector<SURFACE_STATE *> &surface_state,
12236c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                    std::vector<SWAPCHAIN_NODE *> &old_swapchain_state) {
122370342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    if (VK_SUCCESS == result) {
122380342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        for (uint32_t i = 0; i < swapchainCount; i++) {
122390342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            auto swapchain_state = unique_ptr<SWAPCHAIN_NODE>(new SWAPCHAIN_NODE(&pCreateInfos[i], pSwapchains[i]));
122400342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            surface_state[i]->swapchain = swapchain_state.get();
122410342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            dev_data->device_extensions.swapchainMap[pSwapchains[i]] = std::move(swapchain_state);
122420342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        }
122430342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    } else {
122440342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        for (uint32_t i = 0; i < swapchainCount; i++) {
122450342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            surface_state[i]->swapchain = nullptr;
122460342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        }
122470342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    }
122480342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    // Spec requires that even if CreateSharedSwapchainKHR fails, oldSwapchain behaves as replaced.
122490342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    for (uint32_t i = 0; i < swapchainCount; i++) {
122500342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        if (old_swapchain_state[i]) {
122510342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            old_swapchain_state[i]->replaced = true;
122520342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        }
122530342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        surface_state[i]->old_swapchain = old_swapchain_state[i];
122540342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    }
12255c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    return;
12256c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski}
12257c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski
12258c6cd632d064579a64e61d8704b411d0e4ace7adaMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateSharedSwapchainsKHR(VkDevice device, uint32_t swapchainCount,
12259c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                         const VkSwapchainCreateInfoKHR *pCreateInfos,
12260c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                         const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchains) {
12261c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
12262c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    std::vector<SURFACE_STATE *> surface_state;
12263c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    std::vector<SWAPCHAIN_NODE *> old_swapchain_state;
12264c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski
12265c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    if (PreCallValidateCreateSharedSwapchainsKHR(dev_data, swapchainCount, pCreateInfos, pSwapchains, surface_state,
12266c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                 old_swapchain_state)) {
12267c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski        return VK_ERROR_VALIDATION_FAILED_EXT;
12268c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    }
12269c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski
12270c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    VkResult result =
12271c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski        dev_data->dispatch_table.CreateSharedSwapchainsKHR(device, swapchainCount, pCreateInfos, pAllocator, pSwapchains);
12272c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski
12273c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    PostCallRecordCreateSharedSwapchainsKHR(dev_data, result, swapchainCount, pCreateInfos, pSwapchains, surface_state,
12274c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                            old_swapchain_state);
122750342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski
12276c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young    return result;
12277c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young}
12278c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young
1227989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL AcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout,
1228089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                   VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex) {
122815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
1228283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
122831344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
12284b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
12285449670637ef4214b33018f497cf10daeff9dc85bChris Forbes
12286449670637ef4214b33018f497cf10daeff9dc85bChris Forbes    if (fence == VK_NULL_HANDLE && semaphore == VK_NULL_HANDLE) {
12287449670637ef4214b33018f497cf10daeff9dc85bChris Forbes        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
12288d17d86d15a733f1ec988956721ea4b7cdfb6771bChris Forbes                             reinterpret_cast<uint64_t &>(device), __LINE__, DRAWSTATE_SWAPCHAIN_NO_SYNC_FOR_ACQUIRE, "DS",
12289449670637ef4214b33018f497cf10daeff9dc85bChris Forbes                             "vkAcquireNextImageKHR: Semaphore and fence cannot both be VK_NULL_HANDLE. There would be no way "
12290449670637ef4214b33018f497cf10daeff9dc85bChris Forbes                             "to determine the completion of this operation.");
12291449670637ef4214b33018f497cf10daeff9dc85bChris Forbes    }
12292449670637ef4214b33018f497cf10daeff9dc85bChris Forbes
12293f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    auto pSemaphore = getSemaphoreNode(dev_data, semaphore);
12294f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    if (pSemaphore && pSemaphore->signaled) {
1229583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
122962fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                             reinterpret_cast<const uint64_t &>(semaphore), __LINE__, VALIDATION_ERROR_01952, "DS",
122972fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                             "vkAcquireNextImageKHR: Semaphore must not be currently signaled or in a wait state. %s",
122982fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                             validation_error_map[VALIDATION_ERROR_01952]);
122995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
12300f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes
12301f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    auto pFence = getFenceNode(dev_data, fence);
12302f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    if (pFence) {
1230383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis        skip_call |= ValidateFenceForSubmit(dev_data, pFence);
123045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
123054a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes
123064a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes    auto swapchain_data = getSwapchainNode(dev_data, swapchain);
12307fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes
12308fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes    if (swapchain_data->replaced) {
12309fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
12310fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes                             reinterpret_cast<uint64_t &>(swapchain), __LINE__, DRAWSTATE_SWAPCHAIN_REPLACED, "DS",
12311fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes                             "vkAcquireNextImageKHR: This swapchain has been replaced. The application can still "
12312fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes                             "present any images it has acquired, but cannot acquire any more.");
12313fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes    }
12314fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes
123154a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes    auto physical_device_state = getPhysicalDeviceState(dev_data->instance_data, dev_data->physical_device);
123164a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes    if (physical_device_state->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState != UNCALLED) {
123176569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski        uint64_t acquired_images = std::count_if(swapchain_data->images.begin(), swapchain_data->images.end(),
123186569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski                                                 [=](VkImage image) { return getImageState(dev_data, image)->acquired; });
123194a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes        if (acquired_images > swapchain_data->images.size() - physical_device_state->surfaceCapabilities.minImageCount) {
123206569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski            skip_call |=
123216569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
123226569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski                        reinterpret_cast<uint64_t const &>(swapchain), __LINE__, DRAWSTATE_SWAPCHAIN_TOO_MANY_IMAGES, "DS",
123236569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski                        "vkAcquireNextImageKHR: Application has already acquired the maximum number of images (0x%" PRIxLEAST64 ")",
123246569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski                        acquired_images);
123254a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes        }
123264a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes    }
1232775269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis
1232875269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis    if (swapchain_data->images.size() == 0) {
1232975269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
1233075269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis                             reinterpret_cast<uint64_t const &>(swapchain), __LINE__, DRAWSTATE_SWAPCHAIN_IMAGES_NOT_FOUND, "DS",
1233175269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis                             "vkAcquireNextImageKHR: No images found to acquire from. Application probably did not call "
1233275269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis                             "vkGetSwapchainImagesKHR after swapchain creation.");
1233375269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis    }
1233475269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis
12335b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
123361344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
12337cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
12338f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes
123394a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.AcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, pImageIndex);
12340f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes
12341f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    lock.lock();
12342f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    if (result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR) {
12343f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        if (pFence) {
12344f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes            pFence->state = FENCE_INFLIGHT;
12345cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            pFence->signaler.first = VK_NULL_HANDLE;  // ANI isn't on a queue, so this can't participate in a completion proof.
12346f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        }
12347f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes
12348f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        // A successful call to AcquireNextImageKHR counts as a signal operation on semaphore
12349f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        if (pSemaphore) {
12350f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes            pSemaphore->signaled = true;
123519867daedbf52debc77d6568162ee21e071699b80Chris Forbes            pSemaphore->signaler.first = VK_NULL_HANDLE;
12352f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        }
12353220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes
12354220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes        // Mark the image as acquired.
12355220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes        auto image = swapchain_data->images[*pImageIndex];
123561facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        auto image_state = getImageState(dev_data, image);
123571facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        image_state->acquired = true;
123585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
12359f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    lock.unlock();
123601344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
123615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
123625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
123635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12364f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount,
12365f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski                                                        VkPhysicalDevice *pPhysicalDevices) {
1236683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
12367f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes    instance_layer_data *instance_data = get_my_data_ptr(get_dispatch_key(instance), instance_layer_data_map);
12368bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    assert(instance_data);
12369219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes
12370bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    // For this instance, flag when vkEnumeratePhysicalDevices goes to QUERY_COUNT and then QUERY_DETAILS
12371bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    if (NULL == pPhysicalDevices) {
12372bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        instance_data->vkEnumeratePhysicalDevicesState = QUERY_COUNT;
12373f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    } else {
12374bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        if (UNCALLED == instance_data->vkEnumeratePhysicalDevicesState) {
12375bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            // Flag warning here. You can call this without having queried the count, but it may not be
12376bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            // robust on platforms with multiple physical devices.
12377bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            skip_call |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
12378bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis                                 VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, 0, __LINE__, DEVLIMITS_MISSING_QUERY_COUNT, "DL",
12379bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis                                 "Call sequence has vkEnumeratePhysicalDevices() w/ non-NULL pPhysicalDevices. You should first "
12380bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis                                 "call vkEnumeratePhysicalDevices() w/ NULL pPhysicalDevices to query pPhysicalDeviceCount.");
12381cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }  // TODO : Could also flag a warning if re-calling this function in QUERY_DETAILS state
12382bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        else if (instance_data->physical_devices_count != *pPhysicalDeviceCount) {
12383bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            // Having actual count match count from app is not a requirement, so this can be a warning
12384bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            skip_call |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
12385bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis                                 VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVLIMITS_COUNT_MISMATCH, "DL",
12386bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis                                 "Call to vkEnumeratePhysicalDevices() w/ pPhysicalDeviceCount value %u, but actual count "
12387bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis                                 "supported by this instance is %u.",
12388bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis                                 *pPhysicalDeviceCount, instance_data->physical_devices_count);
12389bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        }
12390bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        instance_data->vkEnumeratePhysicalDevicesState = QUERY_DETAILS;
12391f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    }
12392bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    if (skip_call) {
12393bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        return VK_ERROR_VALIDATION_FAILED_EXT;
12394bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    }
12395bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    VkResult result = instance_data->dispatch_table.EnumeratePhysicalDevices(instance, pPhysicalDeviceCount, pPhysicalDevices);
12396bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    if (NULL == pPhysicalDevices) {
12397bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        instance_data->physical_devices_count = *pPhysicalDeviceCount;
12398cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    } else if (result == VK_SUCCESS) {  // Save physical devices
12399bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        for (uint32_t i = 0; i < *pPhysicalDeviceCount; i++) {
12400bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            auto &phys_device_state = instance_data->physical_device_map[pPhysicalDevices[i]];
12401bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            phys_device_state.phys_device = pPhysicalDevices[i];
12402bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            // Init actual features for each physical device
12403bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            instance_data->dispatch_table.GetPhysicalDeviceFeatures(pPhysicalDevices[i], &phys_device_state.features);
12404bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        }
12405bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    }
12406bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    return result;
12407f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski}
12408f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
12409bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
12410bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                  VkQueueFamilyProperties *pQueueFamilyProperties) {
12411cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski    bool skip_call = false;
12412f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes    instance_layer_data *instance_data = get_my_data_ptr(get_dispatch_key(physicalDevice), instance_layer_data_map);
124131f8e18308ae29b5220ce300f0d4dc964bc0941d6Chris Forbes    auto physical_device_state = getPhysicalDeviceState(instance_data, physicalDevice);
124144b293996aa6a9bd92ef1f0175eca4b0e8a9fd9fcChris Forbes    if (physical_device_state) {
124154b293996aa6a9bd92ef1f0175eca4b0e8a9fd9fcChris Forbes        if (!pQueueFamilyProperties) {
124164b293996aa6a9bd92ef1f0175eca4b0e8a9fd9fcChris Forbes            physical_device_state->vkGetPhysicalDeviceQueueFamilyPropertiesState = QUERY_COUNT;
12417bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        } else {
12418cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski            // Verify that for each physical device, this function is called first with NULL pQueueFamilyProperties ptr in order to
12419cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski            // get count
124204b293996aa6a9bd92ef1f0175eca4b0e8a9fd9fcChris Forbes            if (UNCALLED == physical_device_state->vkGetPhysicalDeviceQueueFamilyPropertiesState) {
12421bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                skip_call |=
12422bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
12423bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVLIMITS_MISSING_QUERY_COUNT, "DL",
12424bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "Call sequence has vkGetPhysicalDeviceQueueFamilyProperties() w/ non-NULL "
12425bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "pQueueFamilyProperties. You should first call vkGetPhysicalDeviceQueueFamilyProperties() w/ "
12426bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "NULL pQueueFamilyProperties to query pCount.");
12427cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski            }
12428cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski            // Then verify that pCount that is passed in on second call matches what was returned
124294b293996aa6a9bd92ef1f0175eca4b0e8a9fd9fcChris Forbes            if (physical_device_state->queueFamilyPropertiesCount != *pCount) {
12430cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski                // TODO: this is not a requirement of the Valid Usage section for vkGetPhysicalDeviceQueueFamilyProperties, so
12431cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski                // provide as warning
124321f8e18308ae29b5220ce300f0d4dc964bc0941d6Chris Forbes                skip_call |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
12433bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                     VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVLIMITS_COUNT_MISMATCH, "DL",
12434bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                     "Call to vkGetPhysicalDeviceQueueFamilyProperties() w/ pCount value %u, but actual count "
12435bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                     "supported by this physicalDevice is %u.",
12436bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                     *pCount, physical_device_state->queueFamilyPropertiesCount);
12437cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski            }
124384b293996aa6a9bd92ef1f0175eca4b0e8a9fd9fcChris Forbes            physical_device_state->vkGetPhysicalDeviceQueueFamilyPropertiesState = QUERY_DETAILS;
12439cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski        }
12440cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski        if (skip_call) {
12441cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski            return;
12442cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski        }
124439172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes        instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, pCount, pQueueFamilyProperties);
124444b293996aa6a9bd92ef1f0175eca4b0e8a9fd9fcChris Forbes        if (!pQueueFamilyProperties) {
124454b293996aa6a9bd92ef1f0175eca4b0e8a9fd9fcChris Forbes            physical_device_state->queueFamilyPropertiesCount = *pCount;
12446cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        } else {  // Save queue family properties
124477d8b6ab1b68c397da50bad43deb1fba389ebace7Chris Forbes            if (physical_device_state->queue_family_properties.size() < *pCount)
124487d8b6ab1b68c397da50bad43deb1fba389ebace7Chris Forbes                physical_device_state->queue_family_properties.resize(*pCount);
12449cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski            for (uint32_t i = 0; i < *pCount; i++) {
124507d8b6ab1b68c397da50bad43deb1fba389ebace7Chris Forbes                physical_device_state->queue_family_properties[i] = pQueueFamilyProperties[i];
12451cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski            }
12452cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski        }
12453bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    } else {
124541f8e18308ae29b5220ce300f0d4dc964bc0941d6Chris Forbes        log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0,
124552fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                __LINE__, VALIDATION_ERROR_00028, "DL",
12456226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                "Invalid physicalDevice (0x%p) passed into vkGetPhysicalDeviceQueueFamilyProperties(). %s", physicalDevice,
12457226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                validation_error_map[VALIDATION_ERROR_00028]);
12458cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski    }
12459cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski}
12460cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski
12461bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskitemplate <typename TCreateInfo, typename FPtr>
12462bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic VkResult CreateSurface(VkInstance instance, TCreateInfo const *pCreateInfo, VkAllocationCallbacks const *pAllocator,
12463bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                              VkSurfaceKHR *pSurface, FPtr fptr) {
12464747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    instance_layer_data *instance_data = get_my_data_ptr(get_dispatch_key(instance), instance_layer_data_map);
12465747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
12466747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    // Call down the call chain:
12467747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    VkResult result = (instance_data->dispatch_table.*fptr)(instance, pCreateInfo, pAllocator, pSurface);
12468747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
12469747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    if (result == VK_SUCCESS) {
12470747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        std::unique_lock<std::mutex> lock(global_lock);
12471747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        instance_data->surface_map[*pSurface] = SURFACE_STATE(*pSurface);
12472747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        lock.unlock();
12473747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
12474747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
12475747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return result;
12476747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
12477747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
12478747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR void VKAPI_CALL DestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks *pAllocator) {
12479747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool skip_call = false;
12480747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    instance_layer_data *instance_data = get_my_data_ptr(get_dispatch_key(instance), instance_layer_data_map);
12481747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
12482747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    auto surface_state = getSurfaceState(instance_data, surface);
12483747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
12484747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    if (surface_state) {
12485747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        // TODO: track swapchains created from this surface.
12486747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        instance_data->surface_map.erase(surface);
12487747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
12488747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    lock.unlock();
12489747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
12490747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    if (!skip_call) {
12491747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        // Call down the call chain:
12492747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        instance_data->dispatch_table.DestroySurfaceKHR(instance, surface, pAllocator);
12493747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
12494747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
12495747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
124966f2ed666809272002a31b3b4f8adf6581cb41819Norbert NopperVKAPI_ATTR VkResult VKAPI_CALL CreateDisplayPlaneSurfaceKHR(VkInstance instance, const VkDisplaySurfaceCreateInfoKHR *pCreateInfo,
124976f2ed666809272002a31b3b4f8adf6581cb41819Norbert Nopper                                                            const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
124986f2ed666809272002a31b3b4f8adf6581cb41819Norbert Nopper    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateDisplayPlaneSurfaceKHR);
124996f2ed666809272002a31b3b4f8adf6581cb41819Norbert Nopper}
125006f2ed666809272002a31b3b4f8adf6581cb41819Norbert Nopper
12501747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_ANDROID_KHR
12502747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR *pCreateInfo,
12503747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                       const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
12504747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateAndroidSurfaceKHR);
12505747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
12506cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_ANDROID_KHR
12507747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
12508747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_MIR_KHR
12509747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateMirSurfaceKHR(VkInstance instance, const VkMirSurfaceCreateInfoKHR *pCreateInfo,
12510747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                   const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
12511747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateMirSurfaceKHR);
12512747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
12513cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_MIR_KHR
12514747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
12515747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WAYLAND_KHR
12516747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateWaylandSurfaceKHR(VkInstance instance, const VkWaylandSurfaceCreateInfoKHR *pCreateInfo,
12517747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                       const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
12518a9c6cc532ce0ef61d48d1419a96aae51b0e4c64aTobin Ehlis    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateWaylandSurfaceKHR);
12519747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
12520cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_WAYLAND_KHR
12521747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
12522747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WIN32_KHR
12523747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateWin32SurfaceKHR(VkInstance instance, const VkWin32SurfaceCreateInfoKHR *pCreateInfo,
12524747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                     const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
12525747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateWin32SurfaceKHR);
12526747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
12527cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_WIN32_KHR
12528747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
12529747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XCB_KHR
12530747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateXcbSurfaceKHR(VkInstance instance, const VkXcbSurfaceCreateInfoKHR *pCreateInfo,
12531747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                   const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
12532747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateXcbSurfaceKHR);
12533747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
12534cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_XCB_KHR
12535747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
12536747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XLIB_KHR
12537747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateXlibSurfaceKHR(VkInstance instance, const VkXlibSurfaceCreateInfoKHR *pCreateInfo,
12538bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                    const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
12539747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateXlibSurfaceKHR);
12540747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
12541cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_XLIB_KHR
12542747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
1254340921785005eb449ec7c18229f0d84c879708b8aChris ForbesVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
1254440921785005eb449ec7c18229f0d84c879708b8aChris Forbes                                                                       VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) {
1254540921785005eb449ec7c18229f0d84c879708b8aChris Forbes    auto instance_data = get_my_data_ptr(get_dispatch_key(physicalDevice), instance_layer_data_map);
1254640921785005eb449ec7c18229f0d84c879708b8aChris Forbes
1254740921785005eb449ec7c18229f0d84c879708b8aChris Forbes    std::unique_lock<std::mutex> lock(global_lock);
1254840921785005eb449ec7c18229f0d84c879708b8aChris Forbes    auto physical_device_state = getPhysicalDeviceState(instance_data, physicalDevice);
1254940921785005eb449ec7c18229f0d84c879708b8aChris Forbes    lock.unlock();
1255040921785005eb449ec7c18229f0d84c879708b8aChris Forbes
12551bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result =
12552bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        instance_data->dispatch_table.GetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, pSurfaceCapabilities);
1255340921785005eb449ec7c18229f0d84c879708b8aChris Forbes
1255440921785005eb449ec7c18229f0d84c879708b8aChris Forbes    if (result == VK_SUCCESS) {
1255540921785005eb449ec7c18229f0d84c879708b8aChris Forbes        physical_device_state->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState = QUERY_DETAILS;
1255640921785005eb449ec7c18229f0d84c879708b8aChris Forbes        physical_device_state->surfaceCapabilities = *pSurfaceCapabilities;
1255740921785005eb449ec7c18229f0d84c879708b8aChris Forbes    }
1255840921785005eb449ec7c18229f0d84c879708b8aChris Forbes
1255940921785005eb449ec7c18229f0d84c879708b8aChris Forbes    return result;
1256040921785005eb449ec7c18229f0d84c879708b8aChris Forbes}
1256140921785005eb449ec7c18229f0d84c879708b8aChris Forbes
12562418a8711f3301f3027a900bb45daaf0892f4e644Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex,
12563418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes                                                                  VkSurfaceKHR surface, VkBool32 *pSupported) {
12564418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    auto instance_data = get_my_data_ptr(get_dispatch_key(physicalDevice), instance_layer_data_map);
12565418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
12566418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    auto surface_state = getSurfaceState(instance_data, surface);
12567418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    lock.unlock();
12568418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes
12569bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result =
12570bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        instance_data->dispatch_table.GetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, surface, pSupported);
12571418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes
12572418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    if (result == VK_SUCCESS) {
125736569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski        surface_state->gpu_queue_support[{physicalDevice, queueFamilyIndex}] = (*pSupported != 0);
12574418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    }
12575418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes
12576418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    return result;
12577418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes}
12578418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes
125799e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
125809e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                                                                       uint32_t *pPresentModeCount,
125819e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                                                                       VkPresentModeKHR *pPresentModes) {
125829e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    bool skip_call = false;
125839e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    auto instance_data = get_my_data_ptr(get_dispatch_key(physicalDevice), instance_layer_data_map);
125849e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
125859e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    // TODO: this isn't quite right. available modes may differ by surface AND physical device.
125869e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    auto physical_device_state = getPhysicalDeviceState(instance_data, physicalDevice);
12587bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto &call_state = physical_device_state->vkGetPhysicalDeviceSurfacePresentModesKHRState;
125889e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
125899e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    if (pPresentModes) {
125909e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        // Compare the preliminary value of *pPresentModeCount with the value this time:
12591bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto prev_mode_count = (uint32_t)physical_device_state->present_modes.size();
125929e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        switch (call_state) {
12593cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case UNCALLED:
125949e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                skip_call |= log_msg(
12595bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
12596cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    reinterpret_cast<uint64_t>(physicalDevice), __LINE__, DEVLIMITS_MUST_QUERY_COUNT, "DL",
12597cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "vkGetPhysicalDeviceSurfacePresentModesKHR() called with non-NULL pPresentModeCount; but no prior positive "
12598cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "value has been seen for pPresentModeCount.");
12599cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
12600cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
12601cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // both query count and query details
12602cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (*pPresentModeCount != prev_mode_count) {
12603cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip_call |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
12604cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
12605cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         reinterpret_cast<uint64_t>(physicalDevice), __LINE__, DEVLIMITS_COUNT_MISMATCH, "DL",
12606cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         "vkGetPhysicalDeviceSurfacePresentModesKHR() called with *pPresentModeCount (%u) that "
12607cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         "differs from the value "
12608cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         "(%u) that was returned when pPresentModes was NULL.",
12609cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         *pPresentModeCount, prev_mode_count);
12610cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
12611cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
126129e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
126139e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    }
126149e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    lock.unlock();
126159e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
12616cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
126179e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
12618bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result = instance_data->dispatch_table.GetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, pPresentModeCount,
12619bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                        pPresentModes);
126209e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
126219e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
126229e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        lock.lock();
126239e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
126249e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        if (*pPresentModeCount) {
12625cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (call_state < QUERY_COUNT) call_state = QUERY_COUNT;
126269e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            if (*pPresentModeCount > physical_device_state->present_modes.size())
126279e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                physical_device_state->present_modes.resize(*pPresentModeCount);
126289e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
126299e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        if (pPresentModes) {
12630cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (call_state < QUERY_DETAILS) call_state = QUERY_DETAILS;
126319e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            for (uint32_t i = 0; i < *pPresentModeCount; i++) {
126329e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                physical_device_state->present_modes[i] = pPresentModes[i];
126339e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            }
126349e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
126355faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    }
126365faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
126375faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    return result;
126385faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes}
126395faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
126405faa662f6859b01c72d79027abde363d5f10dcd7Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
126415faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                                                                  uint32_t *pSurfaceFormatCount,
126425faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                                                                  VkSurfaceFormatKHR *pSurfaceFormats) {
126435faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    bool skip_call = false;
126445faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    auto instance_data = get_my_data_ptr(get_dispatch_key(physicalDevice), instance_layer_data_map);
126455faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
126465faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    auto physical_device_state = getPhysicalDeviceState(instance_data, physicalDevice);
12647bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto &call_state = physical_device_state->vkGetPhysicalDeviceSurfaceFormatsKHRState;
126485faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
126495faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    if (pSurfaceFormats) {
12650bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto prev_format_count = (uint32_t)physical_device_state->surface_formats.size();
126515faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
126525faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        switch (call_state) {
12653cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case UNCALLED:
12654cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // Since we haven't recorded a preliminary value of *pSurfaceFormatCount, that likely means that the application
12655cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // didn't
12656cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // previously call this function with a NULL value of pSurfaceFormats:
126575faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                skip_call |= log_msg(
12658bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
12659cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    reinterpret_cast<uint64_t>(physicalDevice), __LINE__, DEVLIMITS_MUST_QUERY_COUNT, "DL",
12660cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "vkGetPhysicalDeviceSurfaceFormatsKHR() called with non-NULL pSurfaceFormatCount; but no prior positive "
12661cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "value has been seen for pSurfaceFormats.");
12662cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
12663cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
12664cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (prev_format_count != *pSurfaceFormatCount) {
12665cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip_call |= log_msg(
12666cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
12667cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, reinterpret_cast<uint64_t>(physicalDevice), __LINE__,
12668cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        DEVLIMITS_COUNT_MISMATCH, "DL",
12669cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "vkGetPhysicalDeviceSurfaceFormatsKHR() called with non-NULL pSurfaceFormatCount, and with pSurfaceFormats "
12670cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "set "
12671cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "to "
12672cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "a value (%u) that is greater than the value (%u) that was returned when pSurfaceFormatCount was NULL.",
12673cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        *pSurfaceFormatCount, prev_format_count);
12674cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
12675cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
126769e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
126779e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    }
126785faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    lock.unlock();
126795faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
12680cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
126819e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
126825faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    // Call down the call chain:
126835faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    auto result = instance_data->dispatch_table.GetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, pSurfaceFormatCount,
126845faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                                                                                   pSurfaceFormats);
126855faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
126865faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
126875faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        lock.lock();
126885faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
126895faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        if (*pSurfaceFormatCount) {
12690cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (call_state < QUERY_COUNT) call_state = QUERY_COUNT;
126915faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            if (*pSurfaceFormatCount > physical_device_state->surface_formats.size())
126925faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                physical_device_state->surface_formats.resize(*pSurfaceFormatCount);
126935faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        }
126945faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        if (pSurfaceFormats) {
12695cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (call_state < QUERY_DETAILS) call_state = QUERY_DETAILS;
126965faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            for (uint32_t i = 0; i < *pSurfaceFormatCount; i++) {
126975faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                physical_device_state->surface_formats[i] = pSurfaceFormats[i];
126985faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            }
126995faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        }
127005faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    }
127019e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    return result;
127029e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes}
127039e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
12704bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateDebugReportCallbackEXT(VkInstance instance,
12705bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                            const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
12706bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                            const VkAllocationCallbacks *pAllocator,
12707bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                            VkDebugReportCallbackEXT *pMsgCallback) {
127088860b85a52096f9f9b28616bc37feed505497a54Chris Forbes    instance_layer_data *instance_data = get_my_data_ptr(get_dispatch_key(instance), instance_layer_data_map);
127099172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    VkResult res = instance_data->dispatch_table.CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
127105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == res) {
12711b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
127128860b85a52096f9f9b28616bc37feed505497a54Chris Forbes        res = layer_create_msg_callback(instance_data->report_data, false, pCreateInfo, pAllocator, pMsgCallback);
127135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
127145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return res;
127155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
127165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12717bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT msgCallback,
1271889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                         const VkAllocationCallbacks *pAllocator) {
127198860b85a52096f9f9b28616bc37feed505497a54Chris Forbes    instance_layer_data *instance_data = get_my_data_ptr(get_dispatch_key(instance), instance_layer_data_map);
127209172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    instance_data->dispatch_table.DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);
12721b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::lock_guard<std::mutex> lock(global_lock);
127228860b85a52096f9f9b28616bc37feed505497a54Chris Forbes    layer_destroy_msg_callback(instance_data->report_data, msgCallback, pAllocator);
127235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
127245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12725bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags,
12726bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 VkDebugReportObjectTypeEXT objType, uint64_t object, size_t location,
12727bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
127288860b85a52096f9f9b28616bc37feed505497a54Chris Forbes    instance_layer_data *instance_data = get_my_data_ptr(get_dispatch_key(instance), instance_layer_data_map);
127299172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    instance_data->dispatch_table.DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, pMsg);
127305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
127315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12732bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties) {
12733a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return util_GetLayerProperties(1, &global_layer, pCount, pProperties);
12734a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu}
12735a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu
12736bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
12737bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                              VkLayerProperties *pProperties) {
12738a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return util_GetLayerProperties(1, &global_layer, pCount, pProperties);
12739a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu}
12740a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu
12741bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
12742bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                    VkExtensionProperties *pProperties) {
12743a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    if (pLayerName && !strcmp(pLayerName, global_layer.layerName))
12744a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu        return util_GetExtensionProperties(1, instance_extensions, pCount, pProperties);
12745a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu
12746a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return VK_ERROR_LAYER_NOT_PRESENT;
12747a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu}
12748a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu
12749bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char *pLayerName,
12750bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                  uint32_t *pCount, VkExtensionProperties *pProperties) {
12751cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (pLayerName && !strcmp(pLayerName, global_layer.layerName)) return util_GetExtensionProperties(0, NULL, pCount, pProperties);
12752a8f4a23b1e9c068717eda47cc583a93f447c77e3Chia-I Wu
12753a8f4a23b1e9c068717eda47cc583a93f447c77e3Chia-I Wu    assert(physicalDevice);
12754a8f4a23b1e9c068717eda47cc583a93f447c77e3Chia-I Wu
127559172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    instance_layer_data *instance_data = get_my_data_ptr(get_dispatch_key(physicalDevice), instance_layer_data_map);
127569172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    return instance_data->dispatch_table.EnumerateDeviceExtensionProperties(physicalDevice, NULL, pCount, pProperties);
1275708939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu}
1275808939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu
12759bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_core_instance_command(const char *name);
127607ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu
12761bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_core_device_command(const char *name);
1276280be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu
12763bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_khr_swapchain_command(const char *name, VkDevice dev);
1276409a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu
12765bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_khr_surface_command(const char *name, VkInstance instance);
12766747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
12767bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_extension_instance_commands(const char *name, VkInstance instance);
12768b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
1276989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice dev, const char *funcName) {
1277080be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    PFN_vkVoidFunction proc = intercept_core_device_command(funcName);
12771cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (proc) return proc;
1277280be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu
1277380be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    assert(dev);
127745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1277509a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu    proc = intercept_khr_swapchain_command(funcName, dev);
12776cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (proc) return proc;
1277709a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu
12778f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(dev), layer_data_map);
127795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
127804a0754042cf090e131e9e769d8a3633c228625beChris Forbes    auto &table = dev_data->dispatch_table;
12781cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!table.GetDeviceProcAddr) return nullptr;
127824a0754042cf090e131e9e769d8a3633c228625beChris Forbes    return table.GetDeviceProcAddr(dev, funcName);
127835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
127845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1278589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetInstanceProcAddr(VkInstance instance, const char *funcName) {
127867ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    PFN_vkVoidFunction proc = intercept_core_instance_command(funcName);
12787cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!proc) proc = intercept_core_device_command(funcName);
12788cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!proc) proc = intercept_khr_swapchain_command(funcName, VK_NULL_HANDLE);
12789cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!proc) proc = intercept_khr_surface_command(funcName, instance);
12790cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (proc) return proc;
127915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
127927ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    assert(instance);
127935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
127948860b85a52096f9f9b28616bc37feed505497a54Chris Forbes    instance_layer_data *instance_data = get_my_data_ptr(get_dispatch_key(instance), instance_layer_data_map);
127958860b85a52096f9f9b28616bc37feed505497a54Chris Forbes    proc = debug_report_get_instance_proc_addr(instance_data->report_data, funcName);
12796cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (proc) return proc;
127975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12798b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    proc = intercept_extension_instance_commands(funcName, instance);
12799cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (proc) return proc;
12800b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
128014a0754042cf090e131e9e769d8a3633c228625beChris Forbes    auto &table = instance_data->dispatch_table;
12802cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!table.GetInstanceProcAddr) return nullptr;
128034a0754042cf090e131e9e769d8a3633c228625beChris Forbes    return table.GetInstanceProcAddr(instance, funcName);
128045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
1280508939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu
12806b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark YoungVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
12807b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    assert(instance);
12808b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
12809b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    instance_layer_data *instance_data = get_my_data_ptr(get_dispatch_key(instance), instance_layer_data_map);
12810b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
12811b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    auto &table = instance_data->dispatch_table;
12812cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!table.GetPhysicalDeviceProcAddr) return nullptr;
12813b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    return table.GetPhysicalDeviceProcAddr(instance, funcName);
12814b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young}
12815b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
12816bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_core_instance_command(const char *name) {
128177ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    static const struct {
128187ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu        const char *name;
128197ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu        PFN_vkVoidFunction proc;
128207ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    } core_instance_commands[] = {
12821bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkGetInstanceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetInstanceProcAddr)},
12822bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vk_layerGetPhysicalDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceProcAddr)},
12823bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkGetDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceProcAddr)},
12824bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkCreateInstance", reinterpret_cast<PFN_vkVoidFunction>(CreateInstance)},
12825bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkCreateDevice", reinterpret_cast<PFN_vkVoidFunction>(CreateDevice)},
12826bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkEnumeratePhysicalDevices", reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDevices)},
12827bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkGetPhysicalDeviceQueueFamilyProperties", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceQueueFamilyProperties)},
12828bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkDestroyInstance", reinterpret_cast<PFN_vkVoidFunction>(DestroyInstance)},
12829bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkEnumerateInstanceLayerProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceLayerProperties)},
12830bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkEnumerateDeviceLayerProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateDeviceLayerProperties)},
12831bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkEnumerateInstanceExtensionProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceExtensionProperties)},
12832bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkEnumerateDeviceExtensionProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateDeviceExtensionProperties)},
128337ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    };
128347ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu
128357ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    for (size_t i = 0; i < ARRAY_SIZE(core_instance_commands); i++) {
12836cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!strcmp(core_instance_commands[i].name, name)) return core_instance_commands[i].proc;
128377ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    }
128387ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu
128397ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    return nullptr;
128407ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu}
128417ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu
12842bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_core_device_command(const char *name) {
1284380be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    static const struct {
1284480be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu        const char *name;
1284580be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu        PFN_vkVoidFunction proc;
1284680be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    } core_device_commands[] = {
12847593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkGetDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceProcAddr)},
12848593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkQueueSubmit", reinterpret_cast<PFN_vkVoidFunction>(QueueSubmit)},
12849593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkWaitForFences", reinterpret_cast<PFN_vkVoidFunction>(WaitForFences)},
12850593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkGetFenceStatus", reinterpret_cast<PFN_vkVoidFunction>(GetFenceStatus)},
12851593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkQueueWaitIdle", reinterpret_cast<PFN_vkVoidFunction>(QueueWaitIdle)},
12852593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDeviceWaitIdle", reinterpret_cast<PFN_vkVoidFunction>(DeviceWaitIdle)},
12853593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkGetDeviceQueue", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceQueue)},
12854593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyInstance", reinterpret_cast<PFN_vkVoidFunction>(DestroyInstance)},
12855593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyDevice", reinterpret_cast<PFN_vkVoidFunction>(DestroyDevice)},
12856593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyFence", reinterpret_cast<PFN_vkVoidFunction>(DestroyFence)},
12857593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkResetFences", reinterpret_cast<PFN_vkVoidFunction>(ResetFences)},
12858593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroySemaphore", reinterpret_cast<PFN_vkVoidFunction>(DestroySemaphore)},
12859593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyEvent", reinterpret_cast<PFN_vkVoidFunction>(DestroyEvent)},
12860593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyQueryPool", reinterpret_cast<PFN_vkVoidFunction>(DestroyQueryPool)},
12861593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyBuffer", reinterpret_cast<PFN_vkVoidFunction>(DestroyBuffer)},
12862593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyBufferView", reinterpret_cast<PFN_vkVoidFunction>(DestroyBufferView)},
12863593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyImage", reinterpret_cast<PFN_vkVoidFunction>(DestroyImage)},
12864593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyImageView", reinterpret_cast<PFN_vkVoidFunction>(DestroyImageView)},
12865593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyShaderModule", reinterpret_cast<PFN_vkVoidFunction>(DestroyShaderModule)},
12866593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyPipeline", reinterpret_cast<PFN_vkVoidFunction>(DestroyPipeline)},
12867593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyPipelineLayout", reinterpret_cast<PFN_vkVoidFunction>(DestroyPipelineLayout)},
12868593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroySampler", reinterpret_cast<PFN_vkVoidFunction>(DestroySampler)},
12869593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyDescriptorSetLayout", reinterpret_cast<PFN_vkVoidFunction>(DestroyDescriptorSetLayout)},
12870593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(DestroyDescriptorPool)},
12871593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyFramebuffer", reinterpret_cast<PFN_vkVoidFunction>(DestroyFramebuffer)},
12872593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyRenderPass", reinterpret_cast<PFN_vkVoidFunction>(DestroyRenderPass)},
12873593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateBuffer", reinterpret_cast<PFN_vkVoidFunction>(CreateBuffer)},
12874593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateBufferView", reinterpret_cast<PFN_vkVoidFunction>(CreateBufferView)},
12875593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateImage", reinterpret_cast<PFN_vkVoidFunction>(CreateImage)},
12876593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateImageView", reinterpret_cast<PFN_vkVoidFunction>(CreateImageView)},
12877593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateFence", reinterpret_cast<PFN_vkVoidFunction>(CreateFence)},
12878593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreatePipelineCache", reinterpret_cast<PFN_vkVoidFunction>(CreatePipelineCache)},
12879593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyPipelineCache", reinterpret_cast<PFN_vkVoidFunction>(DestroyPipelineCache)},
12880593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkGetPipelineCacheData", reinterpret_cast<PFN_vkVoidFunction>(GetPipelineCacheData)},
12881593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkMergePipelineCaches", reinterpret_cast<PFN_vkVoidFunction>(MergePipelineCaches)},
12882593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateGraphicsPipelines", reinterpret_cast<PFN_vkVoidFunction>(CreateGraphicsPipelines)},
12883593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateComputePipelines", reinterpret_cast<PFN_vkVoidFunction>(CreateComputePipelines)},
12884593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateSampler", reinterpret_cast<PFN_vkVoidFunction>(CreateSampler)},
12885593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateDescriptorSetLayout", reinterpret_cast<PFN_vkVoidFunction>(CreateDescriptorSetLayout)},
12886593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreatePipelineLayout", reinterpret_cast<PFN_vkVoidFunction>(CreatePipelineLayout)},
12887593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(CreateDescriptorPool)},
12888593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkResetDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(ResetDescriptorPool)},
12889593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkAllocateDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(AllocateDescriptorSets)},
12890593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkFreeDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(FreeDescriptorSets)},
12891593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkUpdateDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(UpdateDescriptorSets)},
12892593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateCommandPool", reinterpret_cast<PFN_vkVoidFunction>(CreateCommandPool)},
12893593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyCommandPool", reinterpret_cast<PFN_vkVoidFunction>(DestroyCommandPool)},
12894593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkResetCommandPool", reinterpret_cast<PFN_vkVoidFunction>(ResetCommandPool)},
12895593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateQueryPool", reinterpret_cast<PFN_vkVoidFunction>(CreateQueryPool)},
12896593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkAllocateCommandBuffers", reinterpret_cast<PFN_vkVoidFunction>(AllocateCommandBuffers)},
12897593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkFreeCommandBuffers", reinterpret_cast<PFN_vkVoidFunction>(FreeCommandBuffers)},
12898593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkBeginCommandBuffer", reinterpret_cast<PFN_vkVoidFunction>(BeginCommandBuffer)},
12899593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkEndCommandBuffer", reinterpret_cast<PFN_vkVoidFunction>(EndCommandBuffer)},
12900593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkResetCommandBuffer", reinterpret_cast<PFN_vkVoidFunction>(ResetCommandBuffer)},
12901593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdBindPipeline", reinterpret_cast<PFN_vkVoidFunction>(CmdBindPipeline)},
12902593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetViewport", reinterpret_cast<PFN_vkVoidFunction>(CmdSetViewport)},
12903593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetScissor", reinterpret_cast<PFN_vkVoidFunction>(CmdSetScissor)},
12904593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetLineWidth", reinterpret_cast<PFN_vkVoidFunction>(CmdSetLineWidth)},
12905593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetDepthBias", reinterpret_cast<PFN_vkVoidFunction>(CmdSetDepthBias)},
12906593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetBlendConstants", reinterpret_cast<PFN_vkVoidFunction>(CmdSetBlendConstants)},
12907593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetDepthBounds", reinterpret_cast<PFN_vkVoidFunction>(CmdSetDepthBounds)},
12908593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetStencilCompareMask", reinterpret_cast<PFN_vkVoidFunction>(CmdSetStencilCompareMask)},
12909593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetStencilWriteMask", reinterpret_cast<PFN_vkVoidFunction>(CmdSetStencilWriteMask)},
12910593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetStencilReference", reinterpret_cast<PFN_vkVoidFunction>(CmdSetStencilReference)},
12911593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdBindDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(CmdBindDescriptorSets)},
12912593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdBindVertexBuffers", reinterpret_cast<PFN_vkVoidFunction>(CmdBindVertexBuffers)},
12913593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdBindIndexBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdBindIndexBuffer)},
12914593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdDraw", reinterpret_cast<PFN_vkVoidFunction>(CmdDraw)},
12915593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdDrawIndexed", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndexed)},
12916593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdDrawIndirect", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndirect)},
12917593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdDrawIndexedIndirect", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndexedIndirect)},
12918593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdDispatch", reinterpret_cast<PFN_vkVoidFunction>(CmdDispatch)},
12919593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdDispatchIndirect", reinterpret_cast<PFN_vkVoidFunction>(CmdDispatchIndirect)},
12920593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdCopyBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyBuffer)},
12921593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdCopyImage", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyImage)},
12922593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdBlitImage", reinterpret_cast<PFN_vkVoidFunction>(CmdBlitImage)},
12923593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdCopyBufferToImage", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyBufferToImage)},
12924593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdCopyImageToBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyImageToBuffer)},
12925593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdUpdateBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdUpdateBuffer)},
12926593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdFillBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdFillBuffer)},
12927593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdClearColorImage", reinterpret_cast<PFN_vkVoidFunction>(CmdClearColorImage)},
12928593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdClearDepthStencilImage", reinterpret_cast<PFN_vkVoidFunction>(CmdClearDepthStencilImage)},
12929593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdClearAttachments", reinterpret_cast<PFN_vkVoidFunction>(CmdClearAttachments)},
12930593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdResolveImage", reinterpret_cast<PFN_vkVoidFunction>(CmdResolveImage)},
12931593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetEvent", reinterpret_cast<PFN_vkVoidFunction>(CmdSetEvent)},
12932593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdResetEvent", reinterpret_cast<PFN_vkVoidFunction>(CmdResetEvent)},
12933593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdWaitEvents", reinterpret_cast<PFN_vkVoidFunction>(CmdWaitEvents)},
12934593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdPipelineBarrier", reinterpret_cast<PFN_vkVoidFunction>(CmdPipelineBarrier)},
12935593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdBeginQuery", reinterpret_cast<PFN_vkVoidFunction>(CmdBeginQuery)},
12936593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdEndQuery", reinterpret_cast<PFN_vkVoidFunction>(CmdEndQuery)},
12937593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdResetQueryPool", reinterpret_cast<PFN_vkVoidFunction>(CmdResetQueryPool)},
12938593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdCopyQueryPoolResults", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyQueryPoolResults)},
12939593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdPushConstants", reinterpret_cast<PFN_vkVoidFunction>(CmdPushConstants)},
12940593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdWriteTimestamp", reinterpret_cast<PFN_vkVoidFunction>(CmdWriteTimestamp)},
12941593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateFramebuffer", reinterpret_cast<PFN_vkVoidFunction>(CreateFramebuffer)},
12942593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateShaderModule", reinterpret_cast<PFN_vkVoidFunction>(CreateShaderModule)},
12943593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CreateRenderPass)},
12944593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdBeginRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CmdBeginRenderPass)},
12945593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdNextSubpass", reinterpret_cast<PFN_vkVoidFunction>(CmdNextSubpass)},
12946593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdEndRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CmdEndRenderPass)},
12947593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdExecuteCommands", reinterpret_cast<PFN_vkVoidFunction>(CmdExecuteCommands)},
12948593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkSetEvent", reinterpret_cast<PFN_vkVoidFunction>(SetEvent)},
12949593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkMapMemory", reinterpret_cast<PFN_vkVoidFunction>(MapMemory)},
12950593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkUnmapMemory", reinterpret_cast<PFN_vkVoidFunction>(UnmapMemory)},
12951593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkFlushMappedMemoryRanges", reinterpret_cast<PFN_vkVoidFunction>(FlushMappedMemoryRanges)},
12952593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkInvalidateMappedMemoryRanges", reinterpret_cast<PFN_vkVoidFunction>(InvalidateMappedMemoryRanges)},
12953593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkAllocateMemory", reinterpret_cast<PFN_vkVoidFunction>(AllocateMemory)},
12954593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkFreeMemory", reinterpret_cast<PFN_vkVoidFunction>(FreeMemory)},
12955593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkBindBufferMemory", reinterpret_cast<PFN_vkVoidFunction>(BindBufferMemory)},
12956593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkGetBufferMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(GetBufferMemoryRequirements)},
12957593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkGetImageMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(GetImageMemoryRequirements)},
12958593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkGetQueryPoolResults", reinterpret_cast<PFN_vkVoidFunction>(GetQueryPoolResults)},
12959593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkBindImageMemory", reinterpret_cast<PFN_vkVoidFunction>(BindImageMemory)},
12960593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkQueueBindSparse", reinterpret_cast<PFN_vkVoidFunction>(QueueBindSparse)},
12961593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateSemaphore", reinterpret_cast<PFN_vkVoidFunction>(CreateSemaphore)},
12962593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateEvent", reinterpret_cast<PFN_vkVoidFunction>(CreateEvent)},
1296380be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    };
1296480be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu
1296580be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    for (size_t i = 0; i < ARRAY_SIZE(core_device_commands); i++) {
12966cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!strcmp(core_device_commands[i].name, name)) return core_device_commands[i].proc;
1296780be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    }
1296880be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu
1296980be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    return nullptr;
1297080be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu}
1297180be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu
12972bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_khr_swapchain_command(const char *name, VkDevice dev) {
1297309a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu    static const struct {
1297409a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu        const char *name;
1297509a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu        PFN_vkVoidFunction proc;
1297609a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu    } khr_swapchain_commands[] = {
12977bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkCreateSwapchainKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateSwapchainKHR)},
12978bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkDestroySwapchainKHR", reinterpret_cast<PFN_vkVoidFunction>(DestroySwapchainKHR)},
12979bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkGetSwapchainImagesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetSwapchainImagesKHR)},
12980bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkAcquireNextImageKHR", reinterpret_cast<PFN_vkVoidFunction>(AcquireNextImageKHR)},
12981bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkQueuePresentKHR", reinterpret_cast<PFN_vkVoidFunction>(QueuePresentKHR)},
1298209a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu    };
12983c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young    layer_data *dev_data = nullptr;
1298409a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu
129853f6f8132355ebdae2736b31fc20de2ac60a70310Chia-I Wu    if (dev) {
12986c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young        dev_data = get_my_data_ptr(get_dispatch_key(dev), layer_data_map);
12987cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!dev_data->device_extensions.wsi_enabled) return nullptr;
129883f6f8132355ebdae2736b31fc20de2ac60a70310Chia-I Wu    }
1298909a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu
1299009a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu    for (size_t i = 0; i < ARRAY_SIZE(khr_swapchain_commands); i++) {
12991cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!strcmp(khr_swapchain_commands[i].name, name)) return khr_swapchain_commands[i].proc;
1299209a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu    }
1299309a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu
12994c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young    if (dev_data) {
12995cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!dev_data->device_extensions.wsi_display_swapchain_enabled) return nullptr;
12996c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young    }
12997c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young
12998cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!strcmp("vkCreateSharedSwapchainsKHR", name)) return reinterpret_cast<PFN_vkVoidFunction>(CreateSharedSwapchainsKHR);
12999c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young
1300009a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu    return nullptr;
13001747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
13002747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
13003bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_khr_surface_command(const char *name, VkInstance instance) {
13004747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    static const struct {
13005747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        const char *name;
13006747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        PFN_vkVoidFunction proc;
13007747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        bool instance_layer_data::*enable;
13008747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    } khr_surface_commands[] = {
13009747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_ANDROID_KHR
13010747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        {"vkCreateAndroidSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateAndroidSurfaceKHR),
13011bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::androidSurfaceExtensionEnabled},
13012cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_ANDROID_KHR
13013747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_MIR_KHR
13014747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        {"vkCreateMirSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateMirSurfaceKHR),
13015bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::mirSurfaceExtensionEnabled},
13016cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_MIR_KHR
13017747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WAYLAND_KHR
13018747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        {"vkCreateWaylandSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateWaylandSurfaceKHR),
13019bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::waylandSurfaceExtensionEnabled},
13020cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_WAYLAND_KHR
13021747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WIN32_KHR
13022747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        {"vkCreateWin32SurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateWin32SurfaceKHR),
13023bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::win32SurfaceExtensionEnabled},
13024cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_WIN32_KHR
13025747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XCB_KHR
13026747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        {"vkCreateXcbSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateXcbSurfaceKHR),
13027bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::xcbSurfaceExtensionEnabled},
13028cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_XCB_KHR
13029747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XLIB_KHR
13030747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        {"vkCreateXlibSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateXlibSurfaceKHR),
13031bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::xlibSurfaceExtensionEnabled},
13032cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_XLIB_KHR
13033bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkCreateDisplayPlaneSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateDisplayPlaneSurfaceKHR),
13034bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::displayExtensionEnabled},
13035747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        {"vkDestroySurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(DestroySurfaceKHR),
13036bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::surfaceExtensionEnabled},
1303740921785005eb449ec7c18229f0d84c879708b8aChris Forbes        {"vkGetPhysicalDeviceSurfaceCapabilitiesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfaceCapabilitiesKHR),
13038bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::surfaceExtensionEnabled},
13039418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes        {"vkGetPhysicalDeviceSurfaceSupportKHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfaceSupportKHR),
13040bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::surfaceExtensionEnabled},
130419e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        {"vkGetPhysicalDeviceSurfacePresentModesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfacePresentModesKHR),
13042bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::surfaceExtensionEnabled},
130435faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        {"vkGetPhysicalDeviceSurfaceFormatsKHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfaceFormatsKHR),
13044bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::surfaceExtensionEnabled},
13045747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    };
13046747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
13047747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    instance_layer_data *instance_data = nullptr;
13048747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    if (instance) {
13049747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        instance_data = get_my_data_ptr(get_dispatch_key(instance), instance_layer_data_map);
13050747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
13051747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
13052747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    for (size_t i = 0; i < ARRAY_SIZE(khr_surface_commands); i++) {
13053747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(khr_surface_commands[i].name, name)) {
13054cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (instance_data && !(instance_data->*(khr_surface_commands[i].enable))) return nullptr;
13055747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            return khr_surface_commands[i].proc;
13056747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        }
13057747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
13058747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
13059747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return nullptr;
1306009a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu}
1306109a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu
13062bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_extension_instance_commands(const char *name, VkInstance instance) { return NULL; }
13063b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
13064cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski}  // namespace core_validation
13065d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
13066d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu// vk_layer_logging.h expects these to be defined
13067d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
13068bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugReportCallbackEXT(VkInstance instance,
13069bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                              const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
13070bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                              const VkAllocationCallbacks *pAllocator,
13071bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                              VkDebugReportCallbackEXT *pMsgCallback) {
1307289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu    return core_validation::CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
13073d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
13074d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
13075bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT msgCallback,
13076bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                           const VkAllocationCallbacks *pAllocator) {
1307789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu    core_validation::DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);
13078d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
13079d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
13080bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL vkDebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags,
13081bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   VkDebugReportObjectTypeEXT objType, uint64_t object, size_t location,
13082bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
1308389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu    core_validation::DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, pMsg);
13084d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
13085d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
13086a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu// loader-layer interface v0, just wrappers since there is only a layer
13087d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
13088bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
13089bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                      VkExtensionProperties *pProperties) {
13090a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return core_validation::EnumerateInstanceExtensionProperties(pLayerName, pCount, pProperties);
1309108939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu}
1309208939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu
13093bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties(uint32_t *pCount,
13094bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                  VkLayerProperties *pProperties) {
13095a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return core_validation::EnumerateInstanceLayerProperties(pCount, pProperties);
1309608939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu}
1309708939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu
13098bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
13099bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                VkLayerProperties *pProperties) {
13100a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    // the layer command handles VK_NULL_HANDLE just fine internally
13101a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    assert(physicalDevice == VK_NULL_HANDLE);
13102a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return core_validation::EnumerateDeviceLayerProperties(VK_NULL_HANDLE, pCount, pProperties);
13103d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
13104d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
13105d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I WuVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
13106d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu                                                                                    const char *pLayerName, uint32_t *pCount,
13107d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu                                                                                    VkExtensionProperties *pProperties) {
13108a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    // the layer command handles VK_NULL_HANDLE just fine internally
13109a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    assert(physicalDevice == VK_NULL_HANDLE);
13110a8f4a23b1e9c068717eda47cc583a93f447c77e3Chia-I Wu    return core_validation::EnumerateDeviceExtensionProperties(VK_NULL_HANDLE, pLayerName, pCount, pProperties);
13111d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
13112d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
13113d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I WuVK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev, const char *funcName) {
1311489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu    return core_validation::GetDeviceProcAddr(dev, funcName);
13115d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
13116d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
13117d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I WuVK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) {
1311889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu    return core_validation::GetInstanceProcAddr(instance, funcName);
1311908939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu}
13120b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
13121bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_layerGetPhysicalDeviceProcAddr(VkInstance instance,
13122bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                           const char *funcName) {
13123b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    return core_validation::GetPhysicalDeviceProcAddr(instance, funcName);
13124b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young}
13125b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
13126b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark YoungVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct) {
13127b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    assert(pVersionStruct != NULL);
13128b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    assert(pVersionStruct->sType == LAYER_NEGOTIATE_INTERFACE_STRUCT);
13129b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
13130b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    // Fill in the function pointers if our version is at least capable of having the structure contain them.
13131b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    if (pVersionStruct->loaderLayerInterfaceVersion >= 2) {
13132b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        pVersionStruct->pfnGetInstanceProcAddr = vkGetInstanceProcAddr;
13133b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        pVersionStruct->pfnGetDeviceProcAddr = vkGetDeviceProcAddr;
13134b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        pVersionStruct->pfnGetPhysicalDeviceProcAddr = vk_layerGetPhysicalDeviceProcAddr;
13135b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    }
13136b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
13137b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    if (pVersionStruct->loaderLayerInterfaceVersion < CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
13138b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        core_validation::loader_layer_if_version = pVersionStruct->loaderLayerInterfaceVersion;
13139b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    } else if (pVersionStruct->loaderLayerInterfaceVersion > CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
13140b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        pVersionStruct->loaderLayerInterfaceVersion = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
13141b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    }
13142b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
13143b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    return VK_SUCCESS;
13144b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young}
13145