core_validation.cpp revision 7992c34b28dd617787f0e4d34fd023f894495edb
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
85d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wunamespace core_validation {
86d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisusing std::unordered_map;
885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisusing std::unordered_set;
890c55adf45a81f44300db04ec71a797d790ef103cTobin Ehlisusing std::unique_ptr;
900c55adf45a81f44300db04ec71a797d790ef103cTobin Ehlisusing std::vector;
910c55adf45a81f44300db04ec71a797d790ef103cTobin Ehlisusing std::string;
920c55adf45a81f44300db04ec71a797d790ef103cTobin Ehlisusing std::stringstream;
930c55adf45a81f44300db04ec71a797d790ef103cTobin Ehlisusing std::max;
945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// WSI Image Objects bypass usual Image Object creation methods.  A special Memory
965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Object value will be used to identify them internally.
975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic const VkDeviceMemory MEMTRACKER_SWAP_CHAIN_IMAGE_KEY = (VkDeviceMemory)(-1);
98888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis// 2nd special memory handle used to flag object as unbound from memory
99888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlisstatic const VkDeviceMemory MEMORY_UNBOUND = VkDeviceMemory(~((uint64_t)(0)) - 1);
100b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis
1012e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill// A special value of (0xFFFFFFFF, 0xFFFFFFFF) indicates that the surface size will be determined
1022e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill// by the extent of a swapchain targeting the surface.
1032e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madillstatic const uint32_t kSurfaceSizeFromSwapchain = 0xFFFFFFFFu;
1042e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill
1055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstruct devExts {
106e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool wsi_enabled;
107c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young    bool wsi_display_swapchain_enabled;
108bee1d36c54af112766d4e8552ad302f39290683aMark Lobodzinski    bool nv_glsl_shader_enabled;
1093f687bf405355f3eec6bd1bc0e8d04daba37a0f9Tobin Ehlis    unordered_map<VkSwapchainKHR, unique_ptr<SWAPCHAIN_NODE>> swapchainMap;
1105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkImage, VkSwapchainKHR> imageToSwapchainMap;
1115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis};
1125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// fwd decls
1145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstruct shader_module;
1155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
116f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbesstruct instance_layer_data {
117d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    VkInstance instance = VK_NULL_HANDLE;
118d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    debug_report_data *report_data = nullptr;
1195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<VkDebugReportCallbackEXT> logging_callback;
1209172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    VkLayerInstanceDispatchTable dispatch_table;
1219172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes
122219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes    CALL_STATE vkEnumeratePhysicalDevicesState = UNCALLED;
123219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes    uint32_t physical_devices_count = 0;
124b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    CALL_STATE vkEnumeratePhysicalDeviceGroupsState = UNCALLED;
125b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    uint32_t physical_device_groups_count = 0;
126219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes    CHECK_DISABLED disabled = {};
127219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes
128f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes    unordered_map<VkPhysicalDevice, PHYSICAL_DEVICE_STATE> physical_device_map;
129747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    unordered_map<VkSurfaceKHR, SURFACE_STATE> surface_map;
130747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
131747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool surfaceExtensionEnabled = false;
132747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool displayExtensionEnabled = false;
133747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool androidSurfaceExtensionEnabled = false;
134747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool mirSurfaceExtensionEnabled = false;
135747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool waylandSurfaceExtensionEnabled = false;
136747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool win32SurfaceExtensionEnabled = false;
137747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool xcbSurfaceExtensionEnabled = false;
138747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool xlibSurfaceExtensionEnabled = false;
139f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes};
140f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes
141f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbesstruct layer_data {
142f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes    debug_report_data *report_data = nullptr;
1434a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkLayerDispatchTable dispatch_table;
14494c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis
145d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    devExts device_extensions = {};
146cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    unordered_set<VkQueue> queues;  // All queues under given device
1475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Global set of all cmdBuffers that are inFlight on this device
1485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_set<VkCommandBuffer> globalInFlightCmdBuffers;
1495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Layer specific data
150d31a44af6da568692a73201825459689c9431867Tobin Ehlis    unordered_map<VkSampler, unique_ptr<SAMPLER_STATE>> samplerMap;
15179fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis    unordered_map<VkImageView, unique_ptr<IMAGE_VIEW_STATE>> imageViewMap;
1521facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    unordered_map<VkImage, unique_ptr<IMAGE_STATE>> imageMap;
15339267c0c27b8f032f05a6747eb02d4508247fdc1Tobin Ehlis    unordered_map<VkBufferView, unique_ptr<BUFFER_VIEW_STATE>> bufferViewMap;
1545cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    unordered_map<VkBuffer, unique_ptr<BUFFER_STATE>> bufferMap;
1554c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    unordered_map<VkPipeline, PIPELINE_STATE *> pipelineMap;
1568d6a38de0389036581ada119e548180c614fe0efChris Forbes    unordered_map<VkCommandPool, COMMAND_POOL_NODE> commandPoolMap;
157a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis    unordered_map<VkDescriptorPool, DESCRIPTOR_POOL_STATE *> descriptorPoolMap;
158397d27da37095073c8b86f9ff5289d0a39ce486eTobin Ehlis    unordered_map<VkDescriptorSet, cvdescriptorset::DescriptorSet *> setMap;
159cb9ce9e05b8e939d3da35c64997c70049877f4feTobin Ehlis    unordered_map<VkDescriptorSetLayout, cvdescriptorset::DescriptorSetLayout *> descriptorSetLayoutMap;
1605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkPipelineLayout, PIPELINE_LAYOUT_NODE> pipelineLayoutMap;
16157fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    unordered_map<VkDeviceMemory, unique_ptr<DEVICE_MEM_INFO>> memObjMap;
1625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkFence, FENCE_NODE> fenceMap;
16336c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlis    unordered_map<VkQueue, QUEUE_STATE> queueMap;
1644710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis    unordered_map<VkEvent, EVENT_STATE> eventMap;
1655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<QueryObject, bool> queryToStateMap;
1665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkQueryPool, QUERY_POOL_NODE> queryPoolMap;
1675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkSemaphore, SEMAPHORE_NODE> semaphoreMap;
16872d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis    unordered_map<VkCommandBuffer, GLOBAL_CB_NODE *> commandBufferMap;
169c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    unordered_map<VkFramebuffer, unique_ptr<FRAMEBUFFER_STATE>> frameBufferMap;
1705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkImage, vector<ImageSubresourcePair>> imageSubresourceMap;
1715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> imageLayoutMap;
172127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis    unordered_map<VkRenderPass, unique_ptr<RENDER_PASS_STATE>> renderPassMap;
173918c283ac4f8c604b79abd0c8b5706d2a7352a34Chris Forbes    unordered_map<VkShaderModule, unique_ptr<shader_module>> shaderModuleMap;
17407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
175d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    VkDevice device = VK_NULL_HANDLE;
176ec85232c4d8d9ddf7d2ae57cb8203c5ab52c1106Mark Lobodzinski    VkPhysicalDevice physical_device = VK_NULL_HANDLE;
1775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
178cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    instance_layer_data *instance_data = nullptr;  // from device to enclosing instance
17907a464bd7fec9583f346b8c4b8d43c88d2e9ffa4Chris Forbes
180f71dd305f197826a61f398bff725267a20ea1d90Chris Forbes    VkPhysicalDeviceFeatures enabled_features = {};
1815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Device specific data
182d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    PHYS_DEV_PROPERTIES_NODE phys_dev_properties = {};
183d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    VkPhysicalDeviceMemoryProperties phys_dev_mem_props = {};
184e47dbc3f3340fa177d877a67b2adb76a570027e5Mark Lobodzinski    VkPhysicalDeviceProperties phys_dev_props = {};
1855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis};
1865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
187b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis// TODO : Do we need to guard access to layer_data_map w/ lock?
188b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlisstatic unordered_map<void *, layer_data *> layer_data_map;
189f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbesstatic unordered_map<void *, instance_layer_data *> instance_layer_data_map;
190b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis
191b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Youngstatic uint32_t loader_layer_if_version = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
192b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
193e11120777bcd1543455d1de54b89292879bcd2bbChia-I Wustatic const VkLayerProperties global_layer = {
194f1ea418f193d10a8455cdf47e0eeeeb1f4d8b5bfJon Ashburn    "VK_LAYER_LUNARG_core_validation", VK_LAYER_API_VERSION, 1, "LunarG Validation Layer",
195e11120777bcd1543455d1de54b89292879bcd2bbChia-I Wu};
1965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
197cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskitemplate <class TCreateInfo>
198cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskivoid ValidateLayerOrdering(const TCreateInfo &createInfo) {
1995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool foundLayer = false;
2005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < createInfo.enabledLayerCount; ++i) {
201e11120777bcd1543455d1de54b89292879bcd2bbChia-I Wu        if (!strcmp(createInfo.ppEnabledLayerNames[i], global_layer.layerName)) {
2025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            foundLayer = true;
2035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
2045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // This has to be logged to console as we don't have a callback at this point.
2055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!foundLayer && !strcmp(createInfo.ppEnabledLayerNames[0], "VK_LAYER_GOOGLE_unique_objects")) {
206bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            LOGCONSOLE("Cannot activate layer VK_LAYER_GOOGLE_unique_objects prior to activating %s.", global_layer.layerName);
2075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
2085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
2105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Code imported from shader_checker
2125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic void build_def_index(shader_module *);
2135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// A forward iterator over spirv instructions. Provides easy access to len, opcode, and content words
2155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// without the caller needing to care too much about the physical SPIRV module layout.
2165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstruct spirv_inst_iter {
2175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<uint32_t>::const_iterator zero;
2185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<uint32_t>::const_iterator it;
2195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
220b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes    uint32_t len() {
221b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes        auto result = *it >> 16;
222b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes        assert(result > 0);
223b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes        return result;
224b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes    }
225b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes
2265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t opcode() { return *it & 0x0ffffu; }
227b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes
228b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes    uint32_t const &word(unsigned n) {
229b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes        assert(n < len());
230b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes        return it[n];
231b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes    }
232b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes
2335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t offset() { return (uint32_t)(it - zero); }
2345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter() {}
2365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter(std::vector<uint32_t>::const_iterator zero, std::vector<uint32_t>::const_iterator it) : zero(zero), it(it) {}
2385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool operator==(spirv_inst_iter const &other) { return it == other.it; }
2405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool operator!=(spirv_inst_iter const &other) { return it != other.it; }
2425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
243cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    spirv_inst_iter operator++(int) {  // x++
2445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        spirv_inst_iter ii = *this;
2455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        it += len();
2465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return ii;
2475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
249cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    spirv_inst_iter operator++() {  // ++x;
2505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        it += len();
2515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return *this;
2525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
25425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // The iterator and the value are the same thing.
2555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter &operator*() { return *this; }
2565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter const &operator*() const { return *this; }
2575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis};
2585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstruct shader_module {
26025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // The spirv image itself
2615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    vector<uint32_t> words;
26225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // A mapping of <id> to the first word of its def. this is useful because walking type
26325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // trees, constant expressions, etc requires jumping all over the instruction stream.
2645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<unsigned, unsigned> def_index;
265c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski    bool has_valid_spirv;
2665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    shader_module(VkShaderModuleCreateInfo const *pCreateInfo)
2685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        : words((uint32_t *)pCreateInfo->pCode, (uint32_t *)pCreateInfo->pCode + pCreateInfo->codeSize / sizeof(uint32_t)),
269c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski          def_index(),
270c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski          has_valid_spirv(true) {
2715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        build_def_index(this);
2725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
274c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski    shader_module() : has_valid_spirv(false) {}
275c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski
27625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Expose begin() / end() to enable range-based for
277cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    spirv_inst_iter begin() const { return spirv_inst_iter(words.begin(), words.begin() + 5); }  // First insn
278cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    spirv_inst_iter end() const { return spirv_inst_iter(words.begin(), words.end()); }          // Just past last insn
27925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Given an offset into the module, produce an iterator there.
2805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter at(unsigned offset) const { return spirv_inst_iter(words.begin(), words.begin() + offset); }
2815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
28225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Gets an iterator to the definition of an id
2835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter get_def(unsigned id) const {
2845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto it = def_index.find(id);
2855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (it == def_index.end()) {
2865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return end();
2875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
2885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return at(it->second);
2895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis};
2915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// TODO : This can be much smarter, using separate locks for separate global data
293b9e992386a44404152747d66817a733aa127e281Jeremy Hayesstatic std::mutex global_lock;
294593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
29579fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis// Return IMAGE_VIEW_STATE ptr for specified imageView or else NULL
2969a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisIMAGE_VIEW_STATE *GetImageViewState(const layer_data *dev_data, VkImageView image_view) {
2972c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    auto iv_it = dev_data->imageViewMap.find(image_view);
2982c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    if (iv_it == dev_data->imageViewMap.end()) {
2992c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis        return nullptr;
3002c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    }
3012c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    return iv_it->second.get();
3022c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis}
3039a55ca3674bb3fac3fbdfca9515a16a224aa9055Tobin Ehlis// Return sampler node ptr for specified sampler or else NULL
3049a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisSAMPLER_STATE *GetSamplerState(const layer_data *dev_data, VkSampler sampler) {
3052c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    auto sampler_it = dev_data->samplerMap.find(sampler);
3062c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    if (sampler_it == dev_data->samplerMap.end()) {
3079a55ca3674bb3fac3fbdfca9515a16a224aa9055Tobin Ehlis        return nullptr;
3089a55ca3674bb3fac3fbdfca9515a16a224aa9055Tobin Ehlis    }
3099a55ca3674bb3fac3fbdfca9515a16a224aa9055Tobin Ehlis    return sampler_it->second.get();
3109a55ca3674bb3fac3fbdfca9515a16a224aa9055Tobin Ehlis}
3115cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis// Return image state ptr for specified image or else NULL
3129a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisIMAGE_STATE *GetImageState(const layer_data *dev_data, VkImage image) {
3136d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis    auto img_it = dev_data->imageMap.find(image);
3146d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis    if (img_it == dev_data->imageMap.end()) {
3156d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis        return nullptr;
3166d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis    }
3176d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis    return img_it->second.get();
3186d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis}
3195cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis// Return buffer state ptr for specified buffer or else NULL
3209a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisBUFFER_STATE *GetBufferState(const layer_data *dev_data, VkBuffer buffer) {
3212c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    auto buff_it = dev_data->bufferMap.find(buffer);
3222c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    if (buff_it == dev_data->bufferMap.end()) {
3238718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis        return nullptr;
3248718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis    }
3258718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis    return buff_it->second.get();
3268718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis}
327b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis// Return swapchain node for specified swapchain or else NULL
3289a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisSWAPCHAIN_NODE *GetSwapchainNode(const layer_data *dev_data, VkSwapchainKHR swapchain) {
329b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis    auto swp_it = dev_data->device_extensions.swapchainMap.find(swapchain);
330b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis    if (swp_it == dev_data->device_extensions.swapchainMap.end()) {
331b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis        return nullptr;
332b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis    }
3333f687bf405355f3eec6bd1bc0e8d04daba37a0f9Tobin Ehlis    return swp_it->second.get();
334b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis}
335170dc65b45f6bcdec47e02b3aa19435e55b32804Tobin Ehlis// Return swapchain for specified image or else NULL
3369a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisVkSwapchainKHR GetSwapchainFromImage(const layer_data *dev_data, VkImage image) {
337170dc65b45f6bcdec47e02b3aa19435e55b32804Tobin Ehlis    auto img_it = dev_data->device_extensions.imageToSwapchainMap.find(image);
338170dc65b45f6bcdec47e02b3aa19435e55b32804Tobin Ehlis    if (img_it == dev_data->device_extensions.imageToSwapchainMap.end()) {
339170dc65b45f6bcdec47e02b3aa19435e55b32804Tobin Ehlis        return VK_NULL_HANDLE;
340170dc65b45f6bcdec47e02b3aa19435e55b32804Tobin Ehlis    }
341170dc65b45f6bcdec47e02b3aa19435e55b32804Tobin Ehlis    return img_it->second;
342170dc65b45f6bcdec47e02b3aa19435e55b32804Tobin Ehlis}
3432f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis// Return buffer node ptr for specified buffer or else NULL
3449a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisBUFFER_VIEW_STATE *GetBufferViewState(const layer_data *dev_data, VkBufferView buffer_view) {
34551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto bv_it = dev_data->bufferViewMap.find(buffer_view);
34651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (bv_it == dev_data->bufferViewMap.end()) {
3472f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis        return nullptr;
3482f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis    }
3492f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis    return bv_it->second.get();
3502f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis}
3518718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis
3529a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisFENCE_NODE *GetFenceNode(layer_data *dev_data, VkFence fence) {
35366fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    auto it = dev_data->fenceMap.find(fence);
35466fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    if (it == dev_data->fenceMap.end()) {
35566fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes        return nullptr;
35666fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    }
35766fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    return &it->second;
35866fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes}
35966fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes
3609a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisEVENT_STATE *GetEventNode(layer_data *dev_data, VkEvent event) {
3619556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis    auto it = dev_data->eventMap.find(event);
3629556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis    if (it == dev_data->eventMap.end()) {
3639556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis        return nullptr;
3649556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis    }
3659556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis    return &it->second;
3669556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis}
3679556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis
3689a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisQUERY_POOL_NODE *GetQueryPoolNode(layer_data *dev_data, VkQueryPool query_pool) {
369ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    auto it = dev_data->queryPoolMap.find(query_pool);
370ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    if (it == dev_data->queryPoolMap.end()) {
371ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis        return nullptr;
372ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    }
373ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    return &it->second;
374ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis}
375ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis
3769a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisQUEUE_STATE *GetQueueState(layer_data *dev_data, VkQueue queue) {
37766fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    auto it = dev_data->queueMap.find(queue);
37866fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    if (it == dev_data->queueMap.end()) {
37966fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes        return nullptr;
38066fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    }
38166fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    return &it->second;
38266fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes}
38366fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes
3849a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisSEMAPHORE_NODE *GetSemaphoreNode(layer_data *dev_data, VkSemaphore semaphore) {
3855e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes    auto it = dev_data->semaphoreMap.find(semaphore);
3865e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes    if (it == dev_data->semaphoreMap.end()) {
3875e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes        return nullptr;
3885e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes    }
3895e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes    return &it->second;
3905e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes}
3915e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes
3929a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisCOMMAND_POOL_NODE *GetCommandPoolNode(layer_data *dev_data, VkCommandPool pool) {
3938d6a38de0389036581ada119e548180c614fe0efChris Forbes    auto it = dev_data->commandPoolMap.find(pool);
3948d6a38de0389036581ada119e548180c614fe0efChris Forbes    if (it == dev_data->commandPoolMap.end()) {
3958d6a38de0389036581ada119e548180c614fe0efChris Forbes        return nullptr;
3968d6a38de0389036581ada119e548180c614fe0efChris Forbes    }
3978d6a38de0389036581ada119e548180c614fe0efChris Forbes    return &it->second;
3988d6a38de0389036581ada119e548180c614fe0efChris Forbes}
3993bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes
4009a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisPHYSICAL_DEVICE_STATE *GetPhysicalDeviceState(instance_layer_data *instance_data, VkPhysicalDevice phys) {
401f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes    auto it = instance_data->physical_device_map.find(phys);
402f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes    if (it == instance_data->physical_device_map.end()) {
4033bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes        return nullptr;
4043bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes    }
4053bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes    return &it->second;
4063bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes}
4073bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes
4089a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisSURFACE_STATE *GetSurfaceState(instance_layer_data *instance_data, VkSurfaceKHR surface) {
409747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    auto it = instance_data->surface_map.find(surface);
410747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    if (it == instance_data->surface_map.end()) {
411747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        return nullptr;
412747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
413747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return &it->second;
414747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
415747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
416f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis// Return ptr to memory binding for given handle of specified type
41751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic BINDABLE *GetObjectMemBinding(layer_data *dev_data, uint64_t handle, VkDebugReportObjectTypeEXT type) {
4185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (type) {
419cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT:
4209a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            return GetImageState(dev_data, VkImage(handle));
421cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT:
4229a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            return GetBufferState(dev_data, VkBuffer(handle));
423cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
424cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
4255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
42694c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis    return nullptr;
4275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
42872d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis// prototype
4299a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisGLOBAL_CB_NODE *GetCBNode(layer_data const *, const VkCommandBuffer);
43072d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis
4315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Return ptr to info in map container containing mem, or NULL if not found
4325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Calls to this function should be wrapped in mutex
4339a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisDEVICE_MEM_INFO *GetMemObjInfo(const layer_data *dev_data, const VkDeviceMemory mem) {
43457fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    auto mem_it = dev_data->memObjMap.find(mem);
43557fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    if (mem_it == dev_data->memObjMap.end()) {
4365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return NULL;
4375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
43857fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    return mem_it->second.get();
4395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
4405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
44151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void add_mem_obj_info(layer_data *dev_data, void *object, const VkDeviceMemory mem,
4425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                             const VkMemoryAllocateInfo *pAllocateInfo) {
4435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(object != NULL);
4445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
44551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    dev_data->memObjMap[mem] = unique_ptr<DEVICE_MEM_INFO>(new DEVICE_MEM_INFO(object, mem, pAllocateInfo));
4465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
447dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis
448dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis// Helper function to print lowercase string of object type
449dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis//  TODO: Unify string helper functions, this should really come out of a string helper if not there already
450dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlisstatic const char *object_type_to_string(VkDebugReportObjectTypeEXT type) {
451dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis    switch (type) {
452cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT:
453cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "image";
454cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT:
455cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "buffer";
456cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT:
457cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "image view";
458cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT:
459cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "buffer view";
460cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT:
461cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "swapchain";
462cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT:
463cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "descriptor set";
464cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT:
465cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "framebuffer";
466cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT:
467cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "event";
468cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT:
469cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "query pool";
470cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT:
471cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "descriptor pool";
472cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT:
473cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "command pool";
474cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT:
475cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "pipeline";
476cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT:
477cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "sampler";
478cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT:
479cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "renderpass";
480cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT:
481cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "device memory";
482cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT:
483cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "semaphore";
484cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
485cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "unknown";
486dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis    }
487dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis}
488dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis
489cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis// For given bound_object_handle, bound to given mem allocation, verify that the range for the bound object is valid
490f989de4217bce0f293121d0da53dc8328276370fTobin Ehlisstatic bool ValidateMemoryIsValid(layer_data *dev_data, VkDeviceMemory mem, uint64_t bound_object_handle,
491dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis                                  VkDebugReportObjectTypeEXT type, const char *functionName) {
4929a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
493f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    if (mem_info) {
494f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis        if (!mem_info->bound_ranges[bound_object_handle].valid) {
495f48a83f5b5548cd46a12770c7542ff902537ad3eKarl Schultz            return log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
496ea8e85ade623a09c601d939622cbd7740d8d66c9Tobin Ehlis                           reinterpret_cast<uint64_t &>(mem), __LINE__, MEMTRACK_INVALID_MEM_REGION, "MEM",
497dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis                           "%s: Cannot read invalid region of memory allocation 0x%" PRIx64 " for bound %s object 0x%" PRIx64
498dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis                           ", please fill the memory before using.",
499dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis                           functionName, reinterpret_cast<uint64_t &>(mem), object_type_to_string(type), bound_object_handle);
500f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis        }
501f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    }
502f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    return false;
503f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis}
5041facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis// For given image_state
5051facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis//  If mem is special swapchain key, then verify that image_state valid member is true
506f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis//  Else verify that the image's bound memory range is valid
50760568995aca225f81acda8ce40cfabbea2c19397Mark Lobodzinskibool ValidateImageMemoryIsValid(layer_data *dev_data, IMAGE_STATE *image_state, const char *functionName) {
508e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis    if (image_state->binding.mem == MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
5091facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        if (!image_state->valid) {
510f48a83f5b5548cd46a12770c7542ff902537ad3eKarl Schultz            return log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
511e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis                           reinterpret_cast<uint64_t &>(image_state->binding.mem), __LINE__, MEMTRACK_INVALID_MEM_REGION, "MEM",
512414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                           "%s: Cannot read invalid swapchain image 0x%" PRIx64 ", please fill the memory before using.",
5131facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis                           functionName, reinterpret_cast<uint64_t &>(image_state->image));
5145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
5155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
516e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis        return ValidateMemoryIsValid(dev_data, image_state->binding.mem, reinterpret_cast<uint64_t &>(image_state->image),
517dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis                                     VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, functionName);
5185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return false;
5205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
5215cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis// For given buffer_state, verify that the range it's bound to is valid
522c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinskibool ValidateBufferMemoryIsValid(layer_data *dev_data, BUFFER_STATE *buffer_state, const char *functionName) {
5235cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    return ValidateMemoryIsValid(dev_data, buffer_state->binding.mem, reinterpret_cast<uint64_t &>(buffer_state->buffer),
524dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis                                 VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, functionName);
525f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis}
526f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis// For the given memory allocation, set the range bound by the given handle object to the valid param value
527f989de4217bce0f293121d0da53dc8328276370fTobin Ehlisstatic void SetMemoryValid(layer_data *dev_data, VkDeviceMemory mem, uint64_t handle, bool valid) {
5289a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
529f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    if (mem_info) {
530f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis        mem_info->bound_ranges[handle].valid = valid;
531f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    }
532f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis}
533f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis// For given image node
5341facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis//  If mem is special swapchain key, then set entire image_state to valid param value
535f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis//  Else set the image's bound memory range to valid param value
536623784ad78c8b77a78c4db613db974c12e5f5a43Mark Lobodzinskivoid SetImageMemoryValid(layer_data *dev_data, IMAGE_STATE *image_state, bool valid) {
537e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis    if (image_state->binding.mem == MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
5381facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        image_state->valid = valid;
5395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
540e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis        SetMemoryValid(dev_data, image_state->binding.mem, reinterpret_cast<uint64_t &>(image_state->image), valid);
5415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
543f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis// For given buffer node set the buffer's bound memory range to valid param value
544c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinskivoid SetBufferMemoryValid(layer_data *dev_data, BUFFER_STATE *buffer_state, bool valid) {
5455cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    SetMemoryValid(dev_data, buffer_state->binding.mem, reinterpret_cast<uint64_t &>(buffer_state->buffer), valid);
546f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis}
5475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Find CB Info and add mem reference to list container
5485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Find Mem Obj Info and add CB reference to list container
549e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool update_cmd_buf_and_mem_references(layer_data *dev_data, const VkCommandBuffer cb, const VkDeviceMemory mem,
550e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                                              const char *apiName) {
55183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
5525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Skip validation if this image was created through WSI
5545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (mem != MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
5555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // First update CB binding in MemObj mini CB list
5569a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        DEVICE_MEM_INFO *pMemInfo = GetMemObjInfo(dev_data, mem);
5575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (pMemInfo) {
5585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Now update CBInfo's Mem reference list
5599a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            GLOBAL_CB_NODE *cb_node = GetCBNode(dev_data, cb);
560d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis            pMemInfo->cb_bindings.insert(cb_node);
5615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // TODO: keep track of all destroyed CBs so we know if this is a stale or simply invalid object
562d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis            if (cb_node) {
563d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                cb_node->memObjs.insert(mem);
5645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
5655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
5665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
56783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
5685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
569ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
57056f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis// Create binding link between given sampler and command buffer node
571d31a44af6da568692a73201825459689c9431867Tobin Ehlisvoid AddCommandBufferBindingSampler(GLOBAL_CB_NODE *cb_node, SAMPLER_STATE *sampler_state) {
572d31a44af6da568692a73201825459689c9431867Tobin Ehlis    sampler_state->cb_bindings.insert(cb_node);
573d31a44af6da568692a73201825459689c9431867Tobin Ehlis    cb_node->object_bindings.insert(
574d31a44af6da568692a73201825459689c9431867Tobin Ehlis        {reinterpret_cast<uint64_t &>(sampler_state->sampler), VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT});
57556f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis}
57656f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis
57756f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis// Create binding link between given image node and command buffer node
5781facd2c91911508b9fb61f54a56269841299f663Tobin Ehlisvoid AddCommandBufferBindingImage(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, IMAGE_STATE *image_state) {
579ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    // Skip validation if this image was created through WSI
580e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis    if (image_state->binding.mem != MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
581ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // First update CB binding in MemObj mini CB list
582d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis        for (auto mem_binding : image_state->GetBoundMemory()) {
5839a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            DEVICE_MEM_INFO *pMemInfo = GetMemObjInfo(dev_data, mem_binding);
584d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            if (pMemInfo) {
585d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis                pMemInfo->cb_bindings.insert(cb_node);
586d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis                // Now update CBInfo's Mem reference list
587d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis                cb_node->memObjs.insert(mem_binding);
588d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            }
589ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        }
590f940225c9e5e3e14b3f5a32d3ea360b585614600Tobin Ehlis        // Now update cb binding for image
5911facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        cb_node->object_bindings.insert({reinterpret_cast<uint64_t &>(image_state->image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT});
5921facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        image_state->cb_bindings.insert(cb_node);
593ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    }
594ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis}
595ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
59603ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis// Create binding link between given image view node and its image with command buffer node
59703ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlisvoid AddCommandBufferBindingImageView(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, IMAGE_VIEW_STATE *view_state) {
59803ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis    // First add bindings for imageView
59903ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis    view_state->cb_bindings.insert(cb_node);
60003ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis    cb_node->object_bindings.insert(
60103ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis        {reinterpret_cast<uint64_t &>(view_state->image_view), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT});
6029a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto image_state = GetImageState(dev_data, view_state->create_info.image);
60303ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis    // Add bindings for image within imageView
6041facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (image_state) {
6051facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        AddCommandBufferBindingImage(dev_data, cb_node, image_state);
60603ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis    }
60703ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis}
60803ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis
609ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis// Create binding link between given buffer node and command buffer node
6105cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlisvoid AddCommandBufferBindingBuffer(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, BUFFER_STATE *buffer_state) {
611ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    // First update CB binding in MemObj mini CB list
6125cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    for (auto mem_binding : buffer_state->GetBoundMemory()) {
6139a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        DEVICE_MEM_INFO *pMemInfo = GetMemObjInfo(dev_data, mem_binding);
614d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis        if (pMemInfo) {
615d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            pMemInfo->cb_bindings.insert(cb_node);
616d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            // Now update CBInfo's Mem reference list
617d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            cb_node->memObjs.insert(mem_binding);
618d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis        }
619ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    }
620ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    // Now update cb binding for buffer
6215cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    cb_node->object_bindings.insert({reinterpret_cast<uint64_t &>(buffer_state->buffer), VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT});
6225cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    buffer_state->cb_bindings.insert(cb_node);
623ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis}
624ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
62577b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis// Create binding link between given buffer view node and its buffer with command buffer node
62677b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlisvoid AddCommandBufferBindingBufferView(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, BUFFER_VIEW_STATE *view_state) {
62777b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis    // First add bindings for bufferView
62877b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis    view_state->cb_bindings.insert(cb_node);
62977b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis    cb_node->object_bindings.insert(
63077b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis        {reinterpret_cast<uint64_t &>(view_state->buffer_view), VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT});
6319a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto buffer_state = GetBufferState(dev_data, view_state->create_info.buffer);
63277b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis    // Add bindings for buffer within bufferView
6335cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (buffer_state) {
6345cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        AddCommandBufferBindingBuffer(dev_data, cb_node, buffer_state);
63577b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis    }
63677b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis}
63777b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis
638400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis// For every mem obj bound to particular CB, free bindings related to that CB
639d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlisstatic void clear_cmd_buf_and_mem_references(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
640d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis    if (cb_node) {
641d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis        if (cb_node->memObjs.size() > 0) {
642d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis            for (auto mem : cb_node->memObjs) {
6439a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                DEVICE_MEM_INFO *pInfo = GetMemObjInfo(dev_data, mem);
6445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (pInfo) {
645d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                    pInfo->cb_bindings.erase(cb_node);
6465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
6475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
648d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis            cb_node->memObjs.clear();
6495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
650d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis        cb_node->validate_functions.clear();
6515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
653400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis// Overloaded call to above function when GLOBAL_CB_NODE has not already been looked-up
654400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlisstatic void clear_cmd_buf_and_mem_references(layer_data *dev_data, const VkCommandBuffer cb) {
6559a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    clear_cmd_buf_and_mem_references(dev_data, GetCBNode(dev_data, cb));
6565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
6575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
658f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis// Clear a single object binding from given memory object, or report error if binding is missing
659f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlisstatic bool ClearMemoryObjectBinding(layer_data *dev_data, uint64_t handle, VkDebugReportObjectTypeEXT type, VkDeviceMemory mem) {
6609a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
661f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    // This obj is bound to a memory object. Remove the reference to this object in that memory object's list
662d4cd34fd49caa759cf01cafa5fa271401b17c3b9Jeremy Hayes    if (mem_info) {
663d4cd34fd49caa759cf01cafa5fa271401b17c3b9Jeremy Hayes        mem_info->obj_bindings.erase({handle, type});
664f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    }
665f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    return false;
666f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis}
667f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis
668f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis// ClearMemoryObjectBindings clears the binding of objects to memory
669f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis//  For the given object it pulls the memory bindings and makes sure that the bindings
670f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis//  no longer refer to the object being cleared. This occurs when objects are destroyed.
6718c59133586421be878d393799b30044497f77727Mark Lobodzinskibool ClearMemoryObjectBindings(layer_data *dev_data, uint64_t handle, VkDebugReportObjectTypeEXT type) {
672f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    bool skip = false;
673f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    BINDABLE *mem_binding = GetObjectMemBinding(dev_data, handle, type);
674f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    if (mem_binding) {
675f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        if (!mem_binding->sparse) {
676f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis            skip = ClearMemoryObjectBinding(dev_data, handle, type, mem_binding->binding.mem);
677cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        } else {  // Sparse, clear all bindings
678bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            for (auto &sparse_mem_binding : mem_binding->sparse_bindings) {
679f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                skip |= ClearMemoryObjectBinding(dev_data, handle, type, sparse_mem_binding.mem);
6805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
6815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
683f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    return skip;
6845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
6855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
686888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis// For given mem object, verify that it is not null or UNBOUND, if it is, report error. Return skip value.
687888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlisbool VerifyBoundMemoryIsValid(const layer_data *dev_data, VkDeviceMemory mem, uint64_t handle, const char *api_name,
68835ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                              const char *type_name, UNIQUE_VALIDATION_ERROR_CODE error_code) {
689888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    bool result = false;
690888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    if (VK_NULL_HANDLE == mem) {
691888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis        result = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, handle,
692cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                         __LINE__, error_code, "MEM", "%s: Vk%s object 0x%" PRIxLEAST64
693cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                      " used with no memory bound. Memory should be bound by calling "
694cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                      "vkBind%sMemory(). %s",
69535ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                         api_name, type_name, handle, type_name, validation_error_map[error_code]);
696888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    } else if (MEMORY_UNBOUND == mem) {
697888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis        result = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, handle,
698cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                         __LINE__, error_code, "MEM", "%s: Vk%s object 0x%" PRIxLEAST64
699cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                      " used with no memory bound and previously bound memory was freed. "
700cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                      "Memory must not be freed prior to this operation. %s",
70135ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                         api_name, type_name, handle, validation_error_map[error_code]);
702888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    }
703888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    return result;
704888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis}
705888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis
706b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski// Check to see if memory was ever bound to this image
70735ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlisbool ValidateMemoryIsBoundToImage(const layer_data *dev_data, const IMAGE_STATE *image_state, const char *api_name,
70835ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                                  UNIQUE_VALIDATION_ERROR_CODE error_code) {
709b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    bool result = false;
7101facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (0 == (static_cast<uint32_t>(image_state->createInfo.flags) & VK_IMAGE_CREATE_SPARSE_BINDING_BIT)) {
71135ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis        result = VerifyBoundMemoryIsValid(dev_data, image_state->binding.mem,
71235ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                                          reinterpret_cast<const uint64_t &>(image_state->image), api_name, "Image", error_code);
713b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    }
714b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    return result;
715b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski}
716b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski
717b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski// Check to see if memory was bound to this buffer
71835ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlisbool ValidateMemoryIsBoundToBuffer(const layer_data *dev_data, const BUFFER_STATE *buffer_state, const char *api_name,
71935ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                                   UNIQUE_VALIDATION_ERROR_CODE error_code) {
720b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    bool result = false;
7215cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (0 == (static_cast<uint32_t>(buffer_state->createInfo.flags) & VK_BUFFER_CREATE_SPARSE_BINDING_BIT)) {
7225cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        result = VerifyBoundMemoryIsValid(dev_data, buffer_state->binding.mem,
72335ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                                          reinterpret_cast<const uint64_t &>(buffer_state->buffer), api_name, "Buffer", error_code);
724b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    }
725b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    return result;
726b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski}
727b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski
728f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis// SetMemBinding is used to establish immutable, non-sparse binding between a single image/buffer object and memory object
7295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// For NULL mem case, output warning
7305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Make sure given object is in global object map
7315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  IF a previous binding existed, output validation error
7325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Otherwise, add reference from objectInfo to memoryInfo
7335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Add reference off of objInfo
7344f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes// TODO: We may need to refactor or pass in multiple valid usage statements to handle multiple valid usage conditions.
735888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlisstatic bool SetMemBinding(layer_data *dev_data, VkDeviceMemory mem, uint64_t handle, VkDebugReportObjectTypeEXT type,
736888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                          const char *apiName) {
73783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
738f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    // It's an error to bind an object to NULL memory
739d3876b4ff7c293a14f73fe3622513d1fa91bf2d0Jeremy Hayes    if (mem != VK_NULL_HANDLE) {
740f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        BINDABLE *mem_binding = GetObjectMemBinding(dev_data, handle, type);
741888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis        assert(mem_binding);
74210ffe2d353eaff714ed92a2835af77d8b5042d31Cort        if (mem_binding->sparse) {
74310ffe2d353eaff714ed92a2835af77d8b5042d31Cort            UNIQUE_VALIDATION_ERROR_CODE error_code = VALIDATION_ERROR_00804;
74410ffe2d353eaff714ed92a2835af77d8b5042d31Cort            const char *handle_type = "IMAGE";
74510ffe2d353eaff714ed92a2835af77d8b5042d31Cort            if (strcmp(apiName, "vkBindBufferMemory") == 0) {
74610ffe2d353eaff714ed92a2835af77d8b5042d31Cort                error_code = VALIDATION_ERROR_00792;
74710ffe2d353eaff714ed92a2835af77d8b5042d31Cort                handle_type = "BUFFER";
74810ffe2d353eaff714ed92a2835af77d8b5042d31Cort            } else {
74910ffe2d353eaff714ed92a2835af77d8b5042d31Cort                assert(strcmp(apiName, "vkBindImageMemory") == 0);
75010ffe2d353eaff714ed92a2835af77d8b5042d31Cort            }
75110ffe2d353eaff714ed92a2835af77d8b5042d31Cort            skip_call |=
75210ffe2d353eaff714ed92a2835af77d8b5042d31Cort                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
75310ffe2d353eaff714ed92a2835af77d8b5042d31Cort                        reinterpret_cast<uint64_t &>(mem), __LINE__, error_code, "MEM",
75410ffe2d353eaff714ed92a2835af77d8b5042d31Cort                        "In %s, attempting to bind memory (0x%" PRIxLEAST64 ") to object (0x%" PRIxLEAST64
75510ffe2d353eaff714ed92a2835af77d8b5042d31Cort                        ") which was created with sparse memory flags (VK_%s_CREATE_SPARSE_*_BIT). %s",
75610ffe2d353eaff714ed92a2835af77d8b5042d31Cort                        apiName, reinterpret_cast<uint64_t &>(mem), handle, handle_type, validation_error_map[error_code]);
75710ffe2d353eaff714ed92a2835af77d8b5042d31Cort        }
7589a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
759888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis        if (mem_info) {
7609a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            DEVICE_MEM_INFO *prev_binding = GetMemObjInfo(dev_data, mem_binding->binding.mem);
761888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis            if (prev_binding) {
76298c2a17e1a549df84f4239f619bc0955f632cb43Cort                UNIQUE_VALIDATION_ERROR_CODE error_code = VALIDATION_ERROR_00803;
76398c2a17e1a549df84f4239f619bc0955f632cb43Cort                if (strcmp(apiName, "vkBindBufferMemory") == 0) {
76498c2a17e1a549df84f4239f619bc0955f632cb43Cort                    error_code = VALIDATION_ERROR_00791;
76598c2a17e1a549df84f4239f619bc0955f632cb43Cort                } else {
76698c2a17e1a549df84f4239f619bc0955f632cb43Cort                    assert(strcmp(apiName, "vkBindImageMemory") == 0);
76798c2a17e1a549df84f4239f619bc0955f632cb43Cort                }
768888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                skip_call |=
769888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
77098c2a17e1a549df84f4239f619bc0955f632cb43Cort                            reinterpret_cast<uint64_t &>(mem), __LINE__, error_code, "MEM",
771888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                            "In %s, attempting to bind memory (0x%" PRIxLEAST64 ") to object (0x%" PRIxLEAST64
77298c2a17e1a549df84f4239f619bc0955f632cb43Cort                            ") which has already been bound to mem object 0x%" PRIxLEAST64 ". %s",
77398c2a17e1a549df84f4239f619bc0955f632cb43Cort                            apiName, reinterpret_cast<uint64_t &>(mem), handle, reinterpret_cast<uint64_t &>(prev_binding->mem),
77498c2a17e1a549df84f4239f619bc0955f632cb43Cort                            validation_error_map[error_code]);
775f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis            } else if (mem_binding->binding.mem == MEMORY_UNBOUND) {
776888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                skip_call |=
777888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
778888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                            reinterpret_cast<uint64_t &>(mem), __LINE__, MEMTRACK_REBIND_OBJECT, "MEM",
779888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                            "In %s, attempting to bind memory (0x%" PRIxLEAST64 ") to object (0x%" PRIxLEAST64
780888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                            ") which was previous bound to memory that has since been freed. Memory bindings are immutable in "
781888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                            "Vulkan so this attempt to bind to new memory is not allowed.",
782888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                            apiName, reinterpret_cast<uint64_t &>(mem), handle);
7832e415b757c1e43fda35311aad026af8d5c96681cTobin Ehlis            } else {
784888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                mem_info->obj_bindings.insert({handle, type});
7852e415b757c1e43fda35311aad026af8d5c96681cTobin Ehlis                // For image objects, make sure default memory state is correctly set
7862e415b757c1e43fda35311aad026af8d5c96681cTobin Ehlis                // TODO : What's the best/correct way to handle this?
7872e415b757c1e43fda35311aad026af8d5c96681cTobin Ehlis                if (VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT == type) {
7889a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto const image_state = GetImageState(dev_data, VkImage(handle));
7891facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis                    if (image_state) {
7901facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis                        VkImageCreateInfo ici = image_state->createInfo;
7912e415b757c1e43fda35311aad026af8d5c96681cTobin Ehlis                        if (ici.usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
7922e415b757c1e43fda35311aad026af8d5c96681cTobin Ehlis                            // TODO::  More memory state transition stuff.
7935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        }
7945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
7955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
796f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                mem_binding->binding.mem = mem;
7975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
7985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
80083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
8015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
8025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// For NULL mem case, clear any previous binding Else...
8045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Make sure given object is in its object map
8055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  IF a previous binding existed, update binding
8065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Add reference from objectInfo to memoryInfo
8075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Add reference off of object's binding info
8080a1ce3dfd81c9f4efbe46f5ba5ddaea70bc4aa61Chris Forbes// Return VK_TRUE if addition is successful, VK_FALSE otherwise
809f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlisstatic bool SetSparseMemBinding(layer_data *dev_data, MEM_BINDING binding, uint64_t handle, VkDebugReportObjectTypeEXT type,
810f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                                const char *apiName) {
81183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = VK_FALSE;
8125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Handle NULL case separately, just clear previous binding & decrement reference
813f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    if (binding.mem == VK_NULL_HANDLE) {
814f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        // TODO : This should cause the range of the resource to be unbound according to spec
8155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
816f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        BINDABLE *mem_binding = GetObjectMemBinding(dev_data, handle, type);
817f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        assert(mem_binding);
818f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        assert(mem_binding->sparse);
8199a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, binding.mem);
820f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        if (mem_info) {
821f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis            mem_info->obj_bindings.insert({handle, type});
8222e415b757c1e43fda35311aad026af8d5c96681cTobin Ehlis            // Need to set mem binding for this object
823f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis            mem_binding->sparse_bindings.insert(binding);
8245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
82683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
827caf05e0db4959ae196ab34b024f352d9c0326870Tobin Ehlis}
828caf05e0db4959ae196ab34b024f352d9c0326870Tobin Ehlis
8295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Return a string representation of CMD_TYPE enum
8305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic string cmdTypeToString(CMD_TYPE cmd) {
8315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (cmd) {
832cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_BINDPIPELINE:
833cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_BINDPIPELINE";
834cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_BINDPIPELINEDELTA:
835cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_BINDPIPELINEDELTA";
836cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETVIEWPORTSTATE:
837cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETVIEWPORTSTATE";
838cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETLINEWIDTHSTATE:
839cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETLINEWIDTHSTATE";
840cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETDEPTHBIASSTATE:
841cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETDEPTHBIASSTATE";
842cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETBLENDSTATE:
843cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETBLENDSTATE";
844cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETDEPTHBOUNDSSTATE:
845cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETDEPTHBOUNDSSTATE";
846cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETSTENCILREADMASKSTATE:
847cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETSTENCILREADMASKSTATE";
848cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETSTENCILWRITEMASKSTATE:
849cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETSTENCILWRITEMASKSTATE";
850cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETSTENCILREFERENCESTATE:
851cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETSTENCILREFERENCESTATE";
852cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_BINDDESCRIPTORSETS:
853cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_BINDDESCRIPTORSETS";
854cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_BINDINDEXBUFFER:
855cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_BINDINDEXBUFFER";
856cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_BINDVERTEXBUFFER:
857cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_BINDVERTEXBUFFER";
858cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_DRAW:
859cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_DRAW";
860cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_DRAWINDEXED:
861cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_DRAWINDEXED";
862cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_DRAWINDIRECT:
863cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_DRAWINDIRECT";
864cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_DRAWINDEXEDINDIRECT:
865cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_DRAWINDEXEDINDIRECT";
866cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_DISPATCH:
867cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_DISPATCH";
868cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_DISPATCHINDIRECT:
869cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_DISPATCHINDIRECT";
870cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_COPYBUFFER:
871cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_COPYBUFFER";
872cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_COPYIMAGE:
873cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_COPYIMAGE";
874cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_BLITIMAGE:
875cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_BLITIMAGE";
876cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_COPYBUFFERTOIMAGE:
877cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_COPYBUFFERTOIMAGE";
878cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_COPYIMAGETOBUFFER:
879cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_COPYIMAGETOBUFFER";
880cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_CLONEIMAGEDATA:
881cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_CLONEIMAGEDATA";
882cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_UPDATEBUFFER:
883cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_UPDATEBUFFER";
884cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_FILLBUFFER:
885cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_FILLBUFFER";
886cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_CLEARCOLORIMAGE:
887cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_CLEARCOLORIMAGE";
888cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_CLEARATTACHMENTS:
889cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_CLEARCOLORATTACHMENT";
890cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_CLEARDEPTHSTENCILIMAGE:
891cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_CLEARDEPTHSTENCILIMAGE";
892cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_RESOLVEIMAGE:
893cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_RESOLVEIMAGE";
894cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETEVENT:
895cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETEVENT";
896cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_RESETEVENT:
897cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_RESETEVENT";
898cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_WAITEVENTS:
899cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_WAITEVENTS";
900cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_PIPELINEBARRIER:
901cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_PIPELINEBARRIER";
902cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_BEGINQUERY:
903cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_BEGINQUERY";
904cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_ENDQUERY:
905cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_ENDQUERY";
906cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_RESETQUERYPOOL:
907cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_RESETQUERYPOOL";
908cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_COPYQUERYPOOLRESULTS:
909cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_COPYQUERYPOOLRESULTS";
910cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_WRITETIMESTAMP:
911cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_WRITETIMESTAMP";
912cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_INITATOMICCOUNTERS:
913cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_INITATOMICCOUNTERS";
914cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_LOADATOMICCOUNTERS:
915cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_LOADATOMICCOUNTERS";
916cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SAVEATOMICCOUNTERS:
917cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SAVEATOMICCOUNTERS";
918cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_BEGINRENDERPASS:
919cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_BEGINRENDERPASS";
920cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_ENDRENDERPASS:
921cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_ENDRENDERPASS";
922cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
923cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "UNKNOWN";
9245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
9265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// SPIRV utility functions
9285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic void build_def_index(shader_module *module) {
9295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *module) {
9305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        switch (insn.opcode()) {
931cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Types
932cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeVoid:
933cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeBool:
934cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeInt:
935cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeFloat:
936cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeVector:
937cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeMatrix:
938cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeImage:
939cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeSampler:
940cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeSampledImage:
941cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeArray:
942cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeRuntimeArray:
943cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeStruct:
944cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeOpaque:
945cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypePointer:
946cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeFunction:
947cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeEvent:
948cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeDeviceEvent:
949cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeReserveId:
950cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeQueue:
951cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypePipe:
952cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                module->def_index[insn.word(1)] = insn.offset();
953cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
9545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
955cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Fixed constants
956cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstantTrue:
957cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstantFalse:
958cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstant:
959cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstantComposite:
960cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstantSampler:
961cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstantNull:
962cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                module->def_index[insn.word(2)] = insn.offset();
963cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
9645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
965cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Specialization constants
966cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpSpecConstantTrue:
967cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpSpecConstantFalse:
968cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpSpecConstant:
969cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpSpecConstantComposite:
970cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpSpecConstantOp:
971cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                module->def_index[insn.word(2)] = insn.offset();
972cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
9735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
974cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Variables
975cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpVariable:
976cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                module->def_index[insn.word(2)] = insn.offset();
977cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
9785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
979cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Functions
980cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpFunction:
981cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                module->def_index[insn.word(2)] = insn.offset();
982cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
9835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
984cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
985cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // We don't care about any other defs for now.
986cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
9875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
9885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
9905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic spirv_inst_iter find_entrypoint(shader_module *src, char const *name, VkShaderStageFlagBits stageBits) {
9925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
9935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpEntryPoint) {
9945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            auto entrypointName = (char const *)&insn.word(3);
9955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            auto entrypointStageBits = 1u << insn.word(1);
9965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!strcmp(entrypointName, name) && (entrypointStageBits & stageBits)) {
9985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return insn;
9995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
10005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
10015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return src->end();
10045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
10055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic char const *storage_class_name(unsigned sc) {
10075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (sc) {
1008cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassInput:
1009cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "input";
1010cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassOutput:
1011cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "output";
1012cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassUniformConstant:
1013cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "const uniform";
1014cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassUniform:
1015cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "uniform";
1016cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassWorkgroup:
1017cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "workgroup local";
1018cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassCrossWorkgroup:
1019cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "workgroup global";
1020cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassPrivate:
1021cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "private global";
1022cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassFunction:
1023cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "function";
1024cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassGeneric:
1025cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "generic";
1026cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassAtomicCounter:
1027cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "atomic counter";
1028cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassImage:
1029cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "image";
1030cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassPushConstant:
1031cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "push constant";
1032cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1033cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "unknown";
10345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
10365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
103725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// Get the value of an integral constant
10385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisunsigned get_constant_value(shader_module const *src, unsigned id) {
10395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto value = src->get_def(id);
10405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(value != src->end());
10415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (value.opcode() != spv::OpConstant) {
104325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // TODO: Either ensure that the specialization transform is already performed on a module we're
104425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        //       considering here, OR -- specialize on the fly now.
10455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return 1;
10465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return value.word(3);
10495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
10505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10519ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbesstatic void describe_type_inner(std::ostringstream &ss, shader_module const *src, unsigned type) {
10525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto insn = src->get_def(type);
10535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(insn != src->end());
10545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (insn.opcode()) {
1056cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeBool:
1057cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "bool";
1058cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1059cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeInt:
1060cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << (insn.word(3) ? 's' : 'u') << "int" << insn.word(2);
1061cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1062cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeFloat:
1063cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "float" << insn.word(2);
1064cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1065cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeVector:
1066cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "vec" << insn.word(3) << " of ";
1067cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            describe_type_inner(ss, src, insn.word(2));
1068cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1069cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeMatrix:
1070cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "mat" << insn.word(3) << " of ";
1071cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            describe_type_inner(ss, src, insn.word(2));
1072cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1073cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeArray:
1074cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "arr[" << get_constant_value(src, insn.word(3)) << "] of ";
1075cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            describe_type_inner(ss, src, insn.word(2));
1076cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1077cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypePointer:
1078cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "ptr to " << storage_class_name(insn.word(2)) << " ";
1079cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            describe_type_inner(ss, src, insn.word(3));
1080cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1081cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeStruct: {
1082cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "struct of (";
1083cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            for (unsigned i = 2; i < insn.len(); i++) {
1084cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                describe_type_inner(ss, src, insn.word(i));
1085cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (i == insn.len() - 1) {
1086cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    ss << ")";
1087cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                } else {
1088cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    ss << ", ";
1089cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
10909ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes            }
1091cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
10925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
1093cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeSampler:
1094cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "sampler";
1095cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1096cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeSampledImage:
1097cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "sampler+";
1098cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            describe_type_inner(ss, src, insn.word(2));
1099cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1100cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeImage:
1101cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "image(dim=" << insn.word(3) << ", sampled=" << insn.word(7) << ")";
1102cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1103cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1104cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "oddtype";
1105cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
11065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
11075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
11085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11099ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbesstatic std::string describe_type(shader_module const *src, unsigned type) {
11109ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes    std::ostringstream ss;
11119ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes    describe_type_inner(ss, src, type);
11129ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes    return ss.str();
11139ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes}
11149ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes
1115bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool is_narrow_numeric_type(spirv_inst_iter type) {
1116cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (type.opcode() != spv::OpTypeInt && type.opcode() != spv::OpTypeFloat) return false;
111737576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes    return type.word(2) < 64;
111837576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes}
111937576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes
1120bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool types_match(shader_module const *a, shader_module const *b, unsigned a_type, unsigned b_type, bool a_arrayed,
1121bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        bool b_arrayed, bool relaxed) {
112225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Walk two type trees together, and complain about differences
11235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto a_insn = a->get_def(a_type);
11245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto b_insn = b->get_def(b_type);
11255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(a_insn != a->end());
11265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(b_insn != b->end());
11275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11287c755c8aca6857046df9516d8336416165969cb9Chris Forbes    if (a_arrayed && a_insn.opcode() == spv::OpTypeArray) {
112937576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes        return types_match(a, b, a_insn.word(2), b_type, false, b_arrayed, relaxed);
11307c755c8aca6857046df9516d8336416165969cb9Chris Forbes    }
11317c755c8aca6857046df9516d8336416165969cb9Chris Forbes
11325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (b_arrayed && b_insn.opcode() == spv::OpTypeArray) {
113325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // We probably just found the extra level of arrayness in b_type: compare the type inside it to a_type
113437576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes        return types_match(a, b, a_type, b_insn.word(2), a_arrayed, false, relaxed);
113537576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes    }
113637576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes
113737576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes    if (a_insn.opcode() == spv::OpTypeVector && relaxed && is_narrow_numeric_type(b_insn)) {
113837576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes        return types_match(a, b, a_insn.word(2), b_type, a_arrayed, b_arrayed, false);
11395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
11405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (a_insn.opcode() != b_insn.opcode()) {
11425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return false;
11435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
11445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11457c755c8aca6857046df9516d8336416165969cb9Chris Forbes    if (a_insn.opcode() == spv::OpTypePointer) {
114625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Match on pointee type. storage class is expected to differ
114737576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes        return types_match(a, b, a_insn.word(3), b_insn.word(3), a_arrayed, b_arrayed, relaxed);
11487c755c8aca6857046df9516d8336416165969cb9Chris Forbes    }
11497c755c8aca6857046df9516d8336416165969cb9Chris Forbes
11507c755c8aca6857046df9516d8336416165969cb9Chris Forbes    if (a_arrayed || b_arrayed) {
115125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // If we havent resolved array-of-verts by here, we're not going to.
11527c755c8aca6857046df9516d8336416165969cb9Chris Forbes        return false;
11537c755c8aca6857046df9516d8336416165969cb9Chris Forbes    }
11547c755c8aca6857046df9516d8336416165969cb9Chris Forbes
11555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (a_insn.opcode()) {
1156cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeBool:
1157cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return true;
1158cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeInt:
1159cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on width, signedness
1160cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return a_insn.word(2) == b_insn.word(2) && a_insn.word(3) == b_insn.word(3);
1161cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeFloat:
1162cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on width
1163cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return a_insn.word(2) == b_insn.word(2);
1164cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeVector:
1165cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on element type, count.
1166cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (!types_match(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false)) return false;
1167cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (relaxed && is_narrow_numeric_type(a->get_def(a_insn.word(2)))) {
1168cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return a_insn.word(3) >= b_insn.word(3);
1169cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else {
1170cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return a_insn.word(3) == b_insn.word(3);
11715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
1172cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeMatrix:
1173cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on element type, count.
1174cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return types_match(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false) &&
1175cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                   a_insn.word(3) == b_insn.word(3);
1176cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeArray:
1177cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on element type, count. these all have the same layout. we don't get here if b_arrayed. This differs from
1178cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // vector & matrix types in that the array size is the id of a constant instruction, * not a literal within OpTypeArray
1179cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return types_match(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false) &&
1180cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                   get_constant_value(a, a_insn.word(3)) == get_constant_value(b, b_insn.word(3));
1181cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeStruct:
1182cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on all element types
1183cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            {
1184cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (a_insn.len() != b_insn.len()) {
1185cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    return false;  // Structs cannot match if member counts differ
1186cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
11875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1188cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                for (unsigned i = 2; i < a_insn.len(); i++) {
1189cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    if (!types_match(a, b, a_insn.word(i), b_insn.word(i), a_arrayed, b_arrayed, false)) {
1190cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return false;
1191cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    }
1192cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
1193cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski
1194cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return true;
1195cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
1196cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1197cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Remaining types are CLisms, or may not appear in the interfaces we are interested in. Just claim no match.
1198cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return false;
11995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
12005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
12015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic int value_or_default(std::unordered_map<unsigned, unsigned> const &map, unsigned id, int def) {
12035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto it = map.find(id);
12045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (it == map.end())
12055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return def;
12065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    else
12075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return it->second;
12085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
12095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic unsigned get_locations_consumed_by_type(shader_module const *src, unsigned type, bool strip_array_level) {
12115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto insn = src->get_def(type);
12125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(insn != src->end());
12135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (insn.opcode()) {
1215cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypePointer:
1216cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // See through the ptr -- this is only ever at the toplevel for graphics shaders we're never actually passing
1217cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // pointers around.
1218cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_locations_consumed_by_type(src, insn.word(3), strip_array_level);
1219cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeArray:
1220cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (strip_array_level) {
1221cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return get_locations_consumed_by_type(src, insn.word(2), false);
1222cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else {
1223cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return get_constant_value(src, insn.word(3)) * get_locations_consumed_by_type(src, insn.word(2), false);
1224cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
1225cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeMatrix:
1226cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Num locations is the dimension * element size
1227cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return insn.word(3) * get_locations_consumed_by_type(src, insn.word(2), false);
1228cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeVector: {
1229cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            auto scalar_type = src->get_def(insn.word(2));
1230cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            auto bit_width =
1231cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                (scalar_type.opcode() == spv::OpTypeInt || scalar_type.opcode() == spv::OpTypeFloat) ? scalar_type.word(2) : 32;
1232cc52143fc093e1e62d2dacc4abc3966e04b6f6d6Chris Forbes
1233cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Locations are 128-bit wide; 3- and 4-component vectors of 64 bit types require two.
1234cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return (bit_width * insn.word(3) + 127) / 128;
1235cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
1236cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1237cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Everything else is just 1.
1238cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return 1;
12395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1240cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // TODO: extend to handle 64bit scalar types, whose vectors may need multiple locations.
12415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
12425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
12435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1244c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbesstatic unsigned get_locations_consumed_by_format(VkFormat format) {
1245c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes    switch (format) {
1246cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64A64_SFLOAT:
1247cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64A64_SINT:
1248cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64A64_UINT:
1249cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64_SFLOAT:
1250cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64_SINT:
1251cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64_UINT:
1252cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return 2;
1253cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1254cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return 1;
1255c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes    }
1256c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes}
1257c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes
12585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlistypedef std::pair<unsigned, unsigned> location_t;
12595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlistypedef std::pair<unsigned, unsigned> descriptor_slot_t;
12605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstruct interface_var {
12625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t id;
12635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t type_id;
12645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t offset;
1265b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes    bool is_patch;
1266fff9393206f66a154438e16fa0562c989f425498Chris Forbes    bool is_block_member;
1267b0436668e6594b8528e96de7bed208399fb2431dChris Forbes    bool is_relaxed_precision;
126825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // TODO: collect the name, too? Isn't required to be present.
12695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis};
12705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1271031261d21af8907953dd763398ce9a23e65b8749Chris Forbesstruct shader_stage_attributes {
1272031261d21af8907953dd763398ce9a23e65b8749Chris Forbes    char const *const name;
1273031261d21af8907953dd763398ce9a23e65b8749Chris Forbes    bool arrayed_input;
1274031261d21af8907953dd763398ce9a23e65b8749Chris Forbes    bool arrayed_output;
1275031261d21af8907953dd763398ce9a23e65b8749Chris Forbes};
1276031261d21af8907953dd763398ce9a23e65b8749Chris Forbes
1277031261d21af8907953dd763398ce9a23e65b8749Chris Forbesstatic shader_stage_attributes shader_stage_attribs[] = {
1278bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    {"vertex shader", false, false},  {"tessellation control shader", true, true}, {"tessellation evaluation shader", true, false},
1279bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    {"geometry shader", true, false}, {"fragment shader", false, false},
1280031261d21af8907953dd763398ce9a23e65b8749Chris Forbes};
1281031261d21af8907953dd763398ce9a23e65b8749Chris Forbes
12825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic spirv_inst_iter get_struct_type(shader_module const *src, spirv_inst_iter def, bool is_array_of_verts) {
12835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while (true) {
12845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (def.opcode() == spv::OpTypePointer) {
12855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            def = src->get_def(def.word(3));
12865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (def.opcode() == spv::OpTypeArray && is_array_of_verts) {
12875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            def = src->get_def(def.word(2));
12885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            is_array_of_verts = false;
12895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (def.opcode() == spv::OpTypeStruct) {
12905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return def;
12915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
12925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return src->end();
12935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
12945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
12955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
12965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1297bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic void collect_interface_block_members(shader_module const *src, std::map<location_t, interface_var> *out,
12985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                            std::unordered_map<unsigned, unsigned> const &blocks, bool is_array_of_verts,
1299b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes                                            uint32_t id, uint32_t type_id, bool is_patch) {
130025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Walk down the type_id presented, trying to determine whether it's actually an interface block.
1301031261d21af8907953dd763398ce9a23e65b8749Chris Forbes    auto type = get_struct_type(src, src->get_def(type_id), is_array_of_verts && !is_patch);
13025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (type == src->end() || blocks.find(type.word(1)) == blocks.end()) {
130325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // This isn't an interface block.
13045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return;
13055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
13065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> member_components;
13085b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes    std::unordered_map<unsigned, unsigned> member_relaxed_precision;
13095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
131025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Walk all the OpMemberDecorate for type's result id -- first pass, collect components.
13115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
13125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
13135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned member_index = insn.word(2);
13145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(3) == spv::DecorationComponent) {
13165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                unsigned component = insn.word(4);
13175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                member_components[member_index] = component;
13185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
13195b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes
13205b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes            if (insn.word(3) == spv::DecorationRelaxedPrecision) {
13215b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes                member_relaxed_precision[member_index] = 1;
13225b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes            }
13235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
13245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
13255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
132625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Second pass -- produce the output, from Location decorations
13275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
13285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
13295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned member_index = insn.word(2);
13305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned member_type_id = type.word(2 + member_index);
13315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(3) == spv::DecorationLocation) {
13335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                unsigned location = insn.word(4);
13345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                unsigned num_locations = get_locations_consumed_by_type(src, member_type_id, false);
13355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                auto component_it = member_components.find(member_index);
13365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                unsigned component = component_it == member_components.end() ? 0 : component_it->second;
13375b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes                bool is_relaxed_precision = member_relaxed_precision.find(member_index) != member_relaxed_precision.end();
13385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                for (unsigned int offset = 0; offset < num_locations; offset++) {
1340b0436668e6594b8528e96de7bed208399fb2431dChris Forbes                    interface_var v = {};
13415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.id = id;
134225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski                    // TODO: member index in interface_var too?
13435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.type_id = member_type_id;
13445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.offset = offset;
1345b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes                    v.is_patch = is_patch;
1346fff9393206f66a154438e16fa0562c989f425498Chris Forbes                    v.is_block_member = true;
13475b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes                    v.is_relaxed_precision = is_relaxed_precision;
13483a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes                    (*out)[std::make_pair(location + offset, component)] = v;
13495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
13505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
13515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
13525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
13535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
13545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1355bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic std::map<location_t, interface_var> collect_interface_by_location(shader_module const *src, spirv_inst_iter entrypoint,
1356bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                         spv::StorageClass sinterface, bool is_array_of_verts) {
13575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> var_locations;
13585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> var_builtins;
13595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> var_components;
13605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> blocks;
1361b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes    std::unordered_map<unsigned, unsigned> var_patch;
1362b0436668e6594b8528e96de7bed208399fb2431dChris Forbes    std::unordered_map<unsigned, unsigned> var_relaxed_precision;
13635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
136525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // We consider two interface models: SSO rendezvous-by-location, and builtins. Complain about anything that
136625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // fits neither model.
13675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpDecorate) {
13685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationLocation) {
13695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                var_locations[insn.word(1)] = insn.word(3);
13705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
13715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationBuiltIn) {
13735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                var_builtins[insn.word(1)] = insn.word(3);
13745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
13755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationComponent) {
13775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                var_components[insn.word(1)] = insn.word(3);
13785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
13795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationBlock) {
13815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                blocks[insn.word(1)] = 1;
13825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
1383b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes
1384b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes            if (insn.word(2) == spv::DecorationPatch) {
1385b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes                var_patch[insn.word(1)] = 1;
1386b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes            }
1387b0436668e6594b8528e96de7bed208399fb2431dChris Forbes
1388b0436668e6594b8528e96de7bed208399fb2431dChris Forbes            if (insn.word(2) == spv::DecorationRelaxedPrecision) {
1389b0436668e6594b8528e96de7bed208399fb2431dChris Forbes                var_relaxed_precision[insn.word(1)] = 1;
1390b0436668e6594b8528e96de7bed208399fb2431dChris Forbes            }
13915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
13925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
13935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
139425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // TODO: handle grouped decorations
139525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // TODO: handle index=1 dual source outputs from FS -- two vars will have the same location, and we DON'T want to clobber.
13965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
139725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Find the end of the entrypoint's name string. additional zero bytes follow the actual null terminator, to fill out the
139825002b75574f762c62b1a00a595bab04ebb25452Mark 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.
1399c15b801a6e1a5dd5eed09e689aecdde7c4a90a5bMichael Mc Donnell    uint32_t word = 3;
14005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while (entrypoint.word(word) & 0xff000000u) {
14015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        ++word;
14025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
14035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    ++word;
14045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14053a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    std::map<location_t, interface_var> out;
14063a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
14075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (; word < entrypoint.len(); word++) {
14085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto insn = src->get_def(entrypoint.word(word));
14095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        assert(insn != src->end());
14105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        assert(insn.opcode() == spv::OpVariable);
14115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14121d5109d5e0dcc530b27e632e73e1be5e12a28dcdJamie Madill        if (insn.word(3) == static_cast<uint32_t>(sinterface)) {
14135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned id = insn.word(2);
14145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned type = insn.word(1);
14155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            int location = value_or_default(var_locations, id, -1);
14175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            int builtin = value_or_default(var_builtins, id, -1);
1418cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            unsigned component = value_or_default(var_components, id, 0);  // Unspecified is OK, is 0
1419b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes            bool is_patch = var_patch.find(id) != var_patch.end();
1420b0436668e6594b8528e96de7bed208399fb2431dChris Forbes            bool is_relaxed_precision = var_relaxed_precision.find(id) != var_relaxed_precision.end();
14215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
142225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // All variables and interface block members in the Input or Output storage classes must be decorated with either
142325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // a builtin or an explicit location.
142425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            //
142525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // TODO: integrate the interface block support here. For now, don't complain -- a valid SPIRV module will only hit
142625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // this path for the interface block case, as the individual members of the type are decorated, rather than
142725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // variable declarations.
14285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (location != -1) {
143025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski                // A user-defined interface variable, with a location. Where a variable occupied multiple locations, emit
143125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski                // one result for each.
14327c755c8aca6857046df9516d8336416165969cb9Chris Forbes                unsigned num_locations = get_locations_consumed_by_type(src, type, is_array_of_verts && !is_patch);
14335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                for (unsigned int offset = 0; offset < num_locations; offset++) {
1434b0436668e6594b8528e96de7bed208399fb2431dChris Forbes                    interface_var v = {};
14355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.id = id;
14365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.type_id = type;
14375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.offset = offset;
1438b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes                    v.is_patch = is_patch;
1439b0436668e6594b8528e96de7bed208399fb2431dChris Forbes                    v.is_relaxed_precision = is_relaxed_precision;
14405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    out[std::make_pair(location + offset, component)] = v;
14415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
14425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else if (builtin == -1) {
144325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski                // An interface block instance
14443a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes                collect_interface_block_members(src, &out, blocks, is_array_of_verts, id, type, is_patch);
14455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
14465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
14475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
14483a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
14493a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    return out;
14505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
14515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1452cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskistatic std::vector<std::pair<uint32_t, interface_var>> collect_interface_by_input_attachment_index(
1453cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    debug_report_data *report_data, shader_module const *src, std::unordered_set<uint32_t> const &accessible_ids) {
14543a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    std::vector<std::pair<uint32_t, interface_var>> out;
1455745d49409296f060402b57950384caadb636a2b2Chris Forbes
1456745d49409296f060402b57950384caadb636a2b2Chris Forbes    for (auto insn : *src) {
1457745d49409296f060402b57950384caadb636a2b2Chris Forbes        if (insn.opcode() == spv::OpDecorate) {
1458745d49409296f060402b57950384caadb636a2b2Chris Forbes            if (insn.word(2) == spv::DecorationInputAttachmentIndex) {
1459745d49409296f060402b57950384caadb636a2b2Chris Forbes                auto attachment_index = insn.word(3);
1460745d49409296f060402b57950384caadb636a2b2Chris Forbes                auto id = insn.word(1);
1461745d49409296f060402b57950384caadb636a2b2Chris Forbes
1462745d49409296f060402b57950384caadb636a2b2Chris Forbes                if (accessible_ids.count(id)) {
1463745d49409296f060402b57950384caadb636a2b2Chris Forbes                    auto def = src->get_def(id);
1464745d49409296f060402b57950384caadb636a2b2Chris Forbes                    assert(def != src->end());
1465745d49409296f060402b57950384caadb636a2b2Chris Forbes
1466745d49409296f060402b57950384caadb636a2b2Chris Forbes                    if (def.opcode() == spv::OpVariable && insn.word(3) == spv::StorageClassUniformConstant) {
1467e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                        auto num_locations = get_locations_consumed_by_type(src, def.word(1), false);
1468e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                        for (unsigned int offset = 0; offset < num_locations; offset++) {
1469b0436668e6594b8528e96de7bed208399fb2431dChris Forbes                            interface_var v = {};
1470e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                            v.id = id;
1471e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                            v.type_id = def.word(1);
1472e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                            v.offset = offset;
1473e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                            out.emplace_back(attachment_index + offset, v);
1474e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                        }
1475745d49409296f060402b57950384caadb636a2b2Chris Forbes                    }
1476745d49409296f060402b57950384caadb636a2b2Chris Forbes                }
1477745d49409296f060402b57950384caadb636a2b2Chris Forbes            }
1478745d49409296f060402b57950384caadb636a2b2Chris Forbes        }
1479745d49409296f060402b57950384caadb636a2b2Chris Forbes    }
14803a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
14813a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    return out;
1482745d49409296f060402b57950384caadb636a2b2Chris Forbes}
1483745d49409296f060402b57950384caadb636a2b2Chris Forbes
1484cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskistatic std::vector<std::pair<descriptor_slot_t, interface_var>> collect_interface_by_descriptor_slot(
1485cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    debug_report_data *report_data, shader_module const *src, std::unordered_set<uint32_t> const &accessible_ids) {
14865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> var_sets;
14875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> var_bindings;
14885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
149025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // All variables in the Uniform or UniformConstant storage classes are required to be decorated with both
149125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // DecorationDescriptorSet and DecorationBinding.
14925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpDecorate) {
14935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationDescriptorSet) {
14945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                var_sets[insn.word(1)] = insn.word(3);
14955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
14965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationBinding) {
14985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                var_bindings[insn.word(1)] = insn.word(3);
14995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
15005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
15015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
15025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15033a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    std::vector<std::pair<descriptor_slot_t, interface_var>> out;
15043a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
15055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto id : accessible_ids) {
15065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto insn = src->get_def(id);
15075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        assert(insn != src->end());
15085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpVariable &&
15105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            (insn.word(3) == spv::StorageClassUniform || insn.word(3) == spv::StorageClassUniformConstant)) {
15115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned set = value_or_default(var_sets, insn.word(2), 0);
15125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned binding = value_or_default(var_bindings, insn.word(2), 0);
15135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1514b0436668e6594b8528e96de7bed208399fb2431dChris Forbes            interface_var v = {};
15155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            v.id = insn.word(2);
15165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            v.type_id = insn.word(1);
1517cefd4dd8e03c5dae11a05d04a03cb856190358e0Chris Forbes            out.emplace_back(std::make_pair(set, binding), v);
15185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
15195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
15203a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
15213a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    return out;
15225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
15235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1524edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_interface_between_stages(debug_report_data *report_data, shader_module const *producer,
1525031261d21af8907953dd763398ce9a23e65b8749Chris Forbes                                              spirv_inst_iter producer_entrypoint, shader_stage_attributes const *producer_stage,
15265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                              shader_module const *consumer, spirv_inst_iter consumer_entrypoint,
1527031261d21af8907953dd763398ce9a23e65b8749Chris Forbes                                              shader_stage_attributes const *consumer_stage) {
15285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool pass = true;
15295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1530bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto outputs =
1531bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        collect_interface_by_location(producer, producer_entrypoint, spv::StorageClassOutput, producer_stage->arrayed_output);
1532bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto inputs =
1533bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        collect_interface_by_location(consumer, consumer_entrypoint, spv::StorageClassInput, consumer_stage->arrayed_input);
15345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto a_it = outputs.begin();
15365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto b_it = inputs.begin();
15375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
153825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Maps sorted by key (location); walk them together to find mismatches
15395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while ((outputs.size() > 0 && a_it != outputs.end()) || (inputs.size() && b_it != inputs.end())) {
15405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        bool a_at_end = outputs.size() == 0 || a_it == outputs.end();
15415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        bool b_at_end = inputs.size() == 0 || b_it == inputs.end();
15425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto a_first = a_at_end ? std::make_pair(0u, 0u) : a_it->first;
15435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto b_first = b_at_end ? std::make_pair(0u, 0u) : b_it->first;
15445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (b_at_end || ((!a_at_end) && (a_first < b_first))) {
1546bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
1547bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC", "%s writes to output location %u.%u which is not consumed by %s",
1548bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        producer_stage->name, a_first.first, a_first.second, consumer_stage->name)) {
15495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pass = false;
15505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
15515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            a_it++;
15525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (a_at_end || a_first > b_first) {
1553bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
1554bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "%s consumes input location %u.%u which is not written by %s",
1555bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        consumer_stage->name, b_first.first, b_first.second, producer_stage->name)) {
15565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pass = false;
15575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
15585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            b_it++;
15595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
1560fff9393206f66a154438e16fa0562c989f425498Chris Forbes            // subtleties of arrayed interfaces:
1561fff9393206f66a154438e16fa0562c989f425498Chris Forbes            // - if is_patch, then the member is not arrayed, even though the interface may be.
1562fff9393206f66a154438e16fa0562c989f425498Chris Forbes            // - if is_block_member, then the extra array level of an arrayed interface is not
1563fff9393206f66a154438e16fa0562c989f425498Chris Forbes            //   expressed in the member type -- it's expressed in the block type.
15640f44c68c2575ba2fc83d8c8f2f5ea09548f40686Chris Forbes            if (!types_match(producer, consumer, a_it->second.type_id, b_it->second.type_id,
1565fff9393206f66a154438e16fa0562c989f425498Chris Forbes                             producer_stage->arrayed_output && !a_it->second.is_patch && !a_it->second.is_block_member,
1566bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             consumer_stage->arrayed_input && !b_it->second.is_patch && !b_it->second.is_block_member, true)) {
1567bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
1568bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC", "Type mismatch on location %u.%u: '%s' vs '%s'",
1569bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            a_first.first, a_first.second, describe_type(producer, a_it->second.type_id).c_str(),
15709ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes                            describe_type(consumer, b_it->second.type_id).c_str())) {
15715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    pass = false;
15725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
15735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
15740f44c68c2575ba2fc83d8c8f2f5ea09548f40686Chris Forbes            if (a_it->second.is_patch != b_it->second.is_patch) {
1575bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
1576bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
1577f706c50be3a9d4d1e131c2f43ee2fb443f028d30Chris Forbes                            "Decoration mismatch on location %u.%u: is per-%s in %s stage but "
1578bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "per-%s in %s stage",
1579bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            a_first.first, a_first.second, a_it->second.is_patch ? "patch" : "vertex", producer_stage->name,
15800f44c68c2575ba2fc83d8c8f2f5ea09548f40686Chris Forbes                            b_it->second.is_patch ? "patch" : "vertex", consumer_stage->name)) {
15810f44c68c2575ba2fc83d8c8f2f5ea09548f40686Chris Forbes                    pass = false;
15820f44c68c2575ba2fc83d8c8f2f5ea09548f40686Chris Forbes                }
15830f44c68c2575ba2fc83d8c8f2f5ea09548f40686Chris Forbes            }
158417c6bacf91ac671cb33212071b87b8ea782812f5Chris Forbes            if (a_it->second.is_relaxed_precision != b_it->second.is_relaxed_precision) {
1585bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
1586bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
1587bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "Decoration mismatch on location %u.%u: %s and %s stages differ in precision", a_first.first,
1588bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            a_first.second, producer_stage->name, consumer_stage->name)) {
158917c6bacf91ac671cb33212071b87b8ea782812f5Chris Forbes                    pass = false;
159017c6bacf91ac671cb33212071b87b8ea782812f5Chris Forbes                }
159117c6bacf91ac671cb33212071b87b8ea782812f5Chris Forbes            }
15925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            a_it++;
15935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            b_it++;
15945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
15955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
15965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return pass;
15985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
15995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
16005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisenum FORMAT_TYPE {
16015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    FORMAT_TYPE_UNDEFINED,
1602cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    FORMAT_TYPE_FLOAT,  // UNORM, SNORM, FLOAT, USCALED, SSCALED, SRGB -- anything we consider float in the shader
16035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    FORMAT_TYPE_SINT,
16045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    FORMAT_TYPE_UINT,
16055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis};
16065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
16075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic unsigned get_format_type(VkFormat fmt) {
16085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (fmt) {
1609cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_UNDEFINED:
1610cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return FORMAT_TYPE_UNDEFINED;
1611cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R8_SINT:
1612cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R8G8_SINT:
1613cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R8G8B8_SINT:
1614cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R8G8B8A8_SINT:
1615cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R16_SINT:
1616cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R16G16_SINT:
1617cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R16G16B16_SINT:
1618cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R16G16B16A16_SINT:
1619cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R32_SINT:
1620cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R32G32_SINT:
1621cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R32G32B32_SINT:
1622cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R32G32B32A32_SINT:
1623cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64_SINT:
1624cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64_SINT:
1625cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64_SINT:
1626cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64A64_SINT:
1627cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_B8G8R8_SINT:
1628cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_B8G8R8A8_SINT:
1629cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_A8B8G8R8_SINT_PACK32:
1630cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_A2B10G10R10_SINT_PACK32:
1631cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_A2R10G10B10_SINT_PACK32:
1632cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return FORMAT_TYPE_SINT;
1633cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R8_UINT:
1634cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R8G8_UINT:
1635cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R8G8B8_UINT:
1636cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R8G8B8A8_UINT:
1637cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R16_UINT:
1638cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R16G16_UINT:
1639cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R16G16B16_UINT:
1640cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R16G16B16A16_UINT:
1641cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R32_UINT:
1642cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R32G32_UINT:
1643cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R32G32B32_UINT:
1644cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R32G32B32A32_UINT:
1645cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64_UINT:
1646cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64_UINT:
1647cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64_UINT:
1648cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64A64_UINT:
1649cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_B8G8R8_UINT:
1650cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_B8G8R8A8_UINT:
1651cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_A8B8G8R8_UINT_PACK32:
1652cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_A2B10G10R10_UINT_PACK32:
1653cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_A2R10G10B10_UINT_PACK32:
1654cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return FORMAT_TYPE_UINT;
1655cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1656cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return FORMAT_TYPE_FLOAT;
16575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
16585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
16595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
166025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// characterizes a SPIR-V type appearing in an interface to a FF stage, for comparison to a VkFormat's characterization above.
16615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic unsigned get_fundamental_type(shader_module const *src, unsigned type) {
16625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto insn = src->get_def(type);
16635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(insn != src->end());
16645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
16655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (insn.opcode()) {
1666cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeInt:
1667cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return insn.word(3) ? FORMAT_TYPE_SINT : FORMAT_TYPE_UINT;
1668cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeFloat:
1669cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return FORMAT_TYPE_FLOAT;
1670cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeVector:
1671cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_fundamental_type(src, insn.word(2));
1672cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeMatrix:
1673cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_fundamental_type(src, insn.word(2));
1674cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeArray:
1675cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_fundamental_type(src, insn.word(2));
1676cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypePointer:
1677cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_fundamental_type(src, insn.word(3));
1678cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeImage:
1679cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_fundamental_type(src, insn.word(2));
1680cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski
1681cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1682cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return FORMAT_TYPE_UNDEFINED;
16835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
16845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
16855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
16865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic uint32_t get_shader_stage_id(VkShaderStageFlagBits stage) {
16875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t bit_pos = u_ffs(stage);
16885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return bit_pos - 1;
16895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
16905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1691edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_vi_consistency(debug_report_data *report_data, VkPipelineVertexInputStateCreateInfo const *vi) {
169225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Walk the binding descriptions, which describe the step rate and stride of each vertex buffer.  Each binding should
169325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // be specified only once.
16945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<uint32_t, VkVertexInputBindingDescription const *> bindings;
16955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool pass = true;
16965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
16975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (unsigned i = 0; i < vi->vertexBindingDescriptionCount; i++) {
16985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto desc = &vi->pVertexBindingDescriptions[i];
16995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto &binding = bindings[desc->binding];
17005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (binding) {
17014f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes            // TODO: VALIDATION_ERROR_02105 perhaps?
1702bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
1703bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        SHADER_CHECKER_INCONSISTENT_VI, "SC", "Duplicate vertex input binding descriptions for binding %d",
1704bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        desc->binding)) {
17055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pass = false;
17065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
17075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
17085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            binding = desc;
17095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
17105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
17115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return pass;
17135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
17145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1715edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_vi_against_vs_inputs(debug_report_data *report_data, VkPipelineVertexInputStateCreateInfo const *vi,
17165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                          shader_module const *vs, spirv_inst_iter entrypoint) {
17175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool pass = true;
17185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17193a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    auto inputs = collect_interface_by_location(vs, entrypoint, spv::StorageClassInput, false);
17205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
172125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Build index by location
17225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::map<uint32_t, VkVertexInputAttributeDescription const *> attribs;
17235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (vi) {
1724c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes        for (unsigned i = 0; i < vi->vertexAttributeDescriptionCount; i++) {
1725c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes            auto num_locations = get_locations_consumed_by_format(vi->pVertexAttributeDescriptions[i].format);
1726c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes            for (auto j = 0u; j < num_locations; j++) {
1727c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes                attribs[vi->pVertexAttributeDescriptions[i].location + j] = &vi->pVertexAttributeDescriptions[i];
1728c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes            }
1729c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes        }
17305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
17315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto it_a = attribs.begin();
17335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto it_b = inputs.begin();
17341730e0dd28b3abc660b4e4704cf6d414f7fd4ad6Chris Forbes    bool used = false;
17355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while ((attribs.size() > 0 && it_a != attribs.end()) || (inputs.size() > 0 && it_b != inputs.end())) {
17375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        bool a_at_end = attribs.size() == 0 || it_a == attribs.end();
17385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        bool b_at_end = inputs.size() == 0 || it_b == inputs.end();
17395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto a_first = a_at_end ? 0 : it_a->first;
17405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto b_first = b_at_end ? 0 : it_b->first.first;
17415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!a_at_end && (b_at_end || a_first < b_first)) {
17421730e0dd28b3abc660b4e4704cf6d414f7fd4ad6Chris Forbes            if (!used && log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
1743bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 __LINE__, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",
1744bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 "Vertex attribute at location %d not consumed by vertex shader", a_first)) {
17455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pass = false;
17465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
17471730e0dd28b3abc660b4e4704cf6d414f7fd4ad6Chris Forbes            used = false;
17485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            it_a++;
17495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (!b_at_end && (a_at_end || b_first < a_first)) {
1750bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
1751bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "Vertex shader consumes input at location %d but not provided",
17525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        b_first)) {
17535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pass = false;
17545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
17555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            it_b++;
17565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
17575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned attrib_type = get_format_type(it_a->second->format);
17585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned input_type = get_fundamental_type(vs, it_b->second.type_id);
17595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
176025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // Type checking
17615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (attrib_type != FORMAT_TYPE_UNDEFINED && input_type != FORMAT_TYPE_UNDEFINED && attrib_type != input_type) {
1762bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
1763bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
17644b5890faffa54a735782a6b0a628a991ddc86944Mike Weiblen                            "Attribute type of `%s` at location %d does not match vertex shader input type of `%s`",
1765bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            string_VkFormat(it_a->second->format), a_first, describe_type(vs, it_b->second.type_id).c_str())) {
17665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    pass = false;
17675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
17685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
17695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
177025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // OK!
17711730e0dd28b3abc660b4e4704cf6d414f7fd4ad6Chris Forbes            used = true;
17725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            it_b++;
17735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
17745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
17755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return pass;
17775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
17785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1779edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_fs_outputs_against_render_pass(debug_report_data *report_data, shader_module const *fs,
17808da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis                                                    spirv_inst_iter entrypoint, VkRenderPassCreateInfo const *rpci,
17818da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis                                                    uint32_t subpass_index) {
1782025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes    std::map<uint32_t, VkFormat> color_attachments;
17838da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis    auto subpass = rpci->pSubpasses[subpass_index];
17848da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis    for (auto i = 0u; i < subpass.colorAttachmentCount; ++i) {
1785d9da90d92748c37962766868f8b0354637672c2aTobin Ehlis        uint32_t attachment = subpass.pColorAttachments[i].attachment;
1786cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (attachment == VK_ATTACHMENT_UNUSED) continue;
1787d9da90d92748c37962766868f8b0354637672c2aTobin Ehlis        if (rpci->pAttachments[attachment].format != VK_FORMAT_UNDEFINED) {
1788d9da90d92748c37962766868f8b0354637672c2aTobin Ehlis            color_attachments[i] = rpci->pAttachments[attachment].format;
1789025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes        }
1790025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes    }
1791025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes
17925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool pass = true;
17935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
179425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // TODO: dual source blend index (spv::DecIndex, zero if not provided)
17955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17963a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    auto outputs = collect_interface_by_location(fs, entrypoint, spv::StorageClassOutput, false);
17975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1798025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes    auto it_a = outputs.begin();
1799025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes    auto it_b = color_attachments.begin();
18005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
180125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Walk attachment list and outputs together
1802025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes
1803025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes    while ((outputs.size() > 0 && it_a != outputs.end()) || (color_attachments.size() > 0 && it_b != color_attachments.end())) {
1804025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes        bool a_at_end = outputs.size() == 0 || it_a == outputs.end();
1805025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes        bool b_at_end = color_attachments.size() == 0 || it_b == color_attachments.end();
18065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1807025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes        if (!a_at_end && (b_at_end || it_a->first.first < it_b->first)) {
1808bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
1809bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",
1810d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen                        "fragment shader writes to output location %d with no matching attachment", it_a->first.first)) {
18115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pass = false;
18125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
1813025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            it_a++;
1814025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes        } else if (!b_at_end && (a_at_end || it_a->first.first > it_b->first)) {
1815bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
1816bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "Attachment %d not written by fragment shader", it_b->first)) {
18175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pass = false;
18185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
1819025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            it_b++;
18205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
1821025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            unsigned output_type = get_fundamental_type(fs, it_a->second.type_id);
1822025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            unsigned att_type = get_format_type(it_b->second);
18235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
182425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // Type checking
18255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (att_type != FORMAT_TYPE_UNDEFINED && output_type != FORMAT_TYPE_UNDEFINED && att_type != output_type) {
1826bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
1827bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
1828d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen                            "Attachment %d of type `%s` does not match fragment shader output type of `%s`", it_b->first,
1829bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            string_VkFormat(it_b->second), describe_type(fs, it_a->second.type_id).c_str())) {
18305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    pass = false;
18315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
18325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
18335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
183425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // OK!
1835025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            it_a++;
1836025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            it_b++;
18375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
18385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
18395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return pass;
18415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
18425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
184325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// For some analyses, we need to know about all ids referenced by the static call tree of a particular entrypoint. This is
184425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// important for identifying the set of shader resources actually used by an entrypoint, for example.
184525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// Note: we only explore parts of the image which might actually contain ids we care about for the above analyses.
184625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski//  - NOT the shader input/output interfaces.
184725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski//
184825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// TODO: The set of interesting opcodes here was determined by eyeballing the SPIRV spec. It might be worth
184925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// converting parts of this to be generated from the machine-readable spec instead.
18503a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbesstatic std::unordered_set<uint32_t> mark_accessible_ids(shader_module const *src, spirv_inst_iter entrypoint) {
18513a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    std::unordered_set<uint32_t> ids;
18525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_set<uint32_t> worklist;
18535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    worklist.insert(entrypoint.word(2));
18545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while (!worklist.empty()) {
18565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto id_iter = worklist.begin();
18575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto id = *id_iter;
18585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        worklist.erase(id_iter);
18595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto insn = src->get_def(id);
18615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn == src->end()) {
186225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // ID is something we didn't collect in build_def_index. that's OK -- we'll stumble across all kinds of things here
186325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // that we may not care about.
18645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            continue;
18655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
18665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
186725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Try to add to the output set
18685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!ids.insert(id).second) {
1869cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            continue;  // If we already saw this id, we don't want to walk it again.
18705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
18715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        switch (insn.opcode()) {
1873cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpFunction:
1874cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // Scan whole body of the function, enlisting anything interesting
1875cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                while (++insn, insn.opcode() != spv::OpFunctionEnd) {
1876cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    switch (insn.opcode()) {
1877cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpLoad:
1878cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicLoad:
1879cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicExchange:
1880cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicCompareExchange:
1881cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicCompareExchangeWeak:
1882cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicIIncrement:
1883cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicIDecrement:
1884cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicIAdd:
1885cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicISub:
1886cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicSMin:
1887cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicUMin:
1888cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicSMax:
1889cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicUMax:
1890cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicAnd:
1891cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicOr:
1892cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicXor:
1893cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            worklist.insert(insn.word(3));  // ptr
1894cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
1895cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpStore:
1896cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicStore:
1897cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            worklist.insert(insn.word(1));  // ptr
1898cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
1899cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAccessChain:
1900cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpInBoundsAccessChain:
1901cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            worklist.insert(insn.word(3));  // base ptr
1902cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
1903cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpSampledImage:
1904cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleImplicitLod:
1905cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleExplicitLod:
1906cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleDrefImplicitLod:
1907cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleDrefExplicitLod:
1908cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleProjImplicitLod:
1909cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleProjExplicitLod:
1910cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleProjDrefImplicitLod:
1911cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleProjDrefExplicitLod:
1912cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageFetch:
1913cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageGather:
1914cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageDrefGather:
1915cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageRead:
1916cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImage:
1917cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQueryFormat:
1918cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQueryOrder:
1919cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQuerySizeLod:
1920cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQuerySize:
1921cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQueryLod:
1922cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQueryLevels:
1923cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQuerySamples:
1924cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleImplicitLod:
1925cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleExplicitLod:
1926cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleDrefImplicitLod:
1927cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleDrefExplicitLod:
1928cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleProjImplicitLod:
1929cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleProjExplicitLod:
1930cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleProjDrefImplicitLod:
1931cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleProjDrefExplicitLod:
1932cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseFetch:
1933cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseGather:
1934cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseDrefGather:
1935cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageTexelPointer:
1936cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            worklist.insert(insn.word(3));  // Image or sampled image
1937cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
1938cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageWrite:
1939cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            worklist.insert(insn.word(1));  // Image -- different operand order to above
1940cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
1941cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpFunctionCall:
1942cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            for (uint32_t i = 3; i < insn.len(); i++) {
1943cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                worklist.insert(insn.word(i));  // fn itself, and all args
1944cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            }
1945cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
19465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1947cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpExtInst:
1948cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            for (uint32_t i = 5; i < insn.len(); i++) {
1949cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                worklist.insert(insn.word(i));  // Operands to ext inst
1950cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            }
1951cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
19525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
19535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
1954cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
19555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
19565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
19573a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
19583a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    return ids;
19595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
19605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1961edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_push_constant_block_against_pipeline(debug_report_data *report_data,
1962416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis                                                          std::vector<VkPushConstantRange> const *push_constant_ranges,
19635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                          shader_module const *src, spirv_inst_iter type,
19645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                          VkShaderStageFlagBits stage) {
19655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool pass = true;
19665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
196725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Strip off ptrs etc
19685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    type = get_struct_type(src, type, false);
19695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(type != src->end());
19705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
197125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Validate directly off the offsets. this isn't quite correct for arrays and matrices, but is a good first step.
197225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // TODO: arrays, matrices, weird sizes
19735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
19745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
19755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(3) == spv::DecorationOffset) {
19765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                unsigned offset = insn.word(4);
1977cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto size = 4;  // Bytes; TODO: calculate this based on the type
19785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
19795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                bool found_range = false;
1980416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis                for (auto const &range : *push_constant_ranges) {
19815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    if (range.offset <= offset && range.offset + range.size >= offset + size) {
19825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        found_range = true;
19835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
19845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        if ((range.stageFlags & stage) == 0) {
1985bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
1986bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        SHADER_CHECKER_PUSH_CONSTANT_NOT_ACCESSIBLE_FROM_STAGE, "SC",
19875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                        "Push constant range covering variable starting at "
19885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                        "offset %u not accessible from stage %s",
19895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                        offset, string_VkShaderStageFlagBits(stage))) {
19905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                pass = false;
19915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                            }
19925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        }
19935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
19945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        break;
19955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
19965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
19975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
19985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (!found_range) {
1999bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
2000bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                SHADER_CHECKER_PUSH_CONSTANT_OUT_OF_RANGE, "SC",
20015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                "Push constant range covering variable starting at "
20025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                "offset %u not declared in layout",
20035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                offset)) {
20045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        pass = false;
20055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
20065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
20075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
20085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
20095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
20105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return pass;
20125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
20135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2014edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_push_constant_usage(debug_report_data *report_data,
2015416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis                                         std::vector<VkPushConstantRange> const *push_constant_ranges, shader_module const *src,
20165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                         std::unordered_set<uint32_t> accessible_ids, VkShaderStageFlagBits stage) {
20175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool pass = true;
20185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto id : accessible_ids) {
20205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto def_insn = src->get_def(id);
20215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (def_insn.opcode() == spv::OpVariable && def_insn.word(3) == spv::StorageClassPushConstant) {
2022416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis            pass &= validate_push_constant_block_against_pipeline(report_data, push_constant_ranges, src,
2023416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis                                                                  src->get_def(def_insn.word(1)), stage);
20245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
20255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
20265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return pass;
20285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
20295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2030fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis// For given pipelineLayout verify that the set_layout_node at slot.first
2031fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis//  has the requested binding at slot.second and return ptr to that binding
2032bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic VkDescriptorSetLayoutBinding const *get_descriptor_binding(PIPELINE_LAYOUT_NODE const *pipelineLayout,
2033bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                  descriptor_slot_t slot) {
2034cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!pipelineLayout) return nullptr;
20355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2036cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (slot.first >= pipelineLayout->set_layouts.size()) return nullptr;
20375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2038416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis    return pipelineLayout->set_layouts[slot.first]->GetDescriptorSetLayoutBindingPtrFromBinding(slot.second);
20395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
20405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Check object status for selected flag state
204251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool validate_status(layer_data *dev_data, GLOBAL_CB_NODE *pNode, CBStatusFlags status_mask, VkFlags msg_flags,
20434f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                            const char *fail_msg, UNIQUE_VALIDATION_ERROR_CODE const msg_code) {
20443d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    if (!(pNode->status & status_mask)) {
20454f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes        char const *const message = validation_error_map[msg_code];
204651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        return log_msg(dev_data->report_data, msg_flags, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
20474f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                       reinterpret_cast<const uint64_t &>(pNode->commandBuffer), __LINE__, msg_code, "DS",
20484f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                       "command buffer object 0x%p: %s. %s.", pNode->commandBuffer, fail_msg, message);
20495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2050e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    return false;
20515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
20525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Retrieve pipeline node ptr for given pipeline object
205451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic PIPELINE_STATE *getPipelineState(layer_data const *dev_data, VkPipeline pipeline) {
205551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->pipelineMap.find(pipeline);
205651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->pipelineMap.end()) {
2057ea8349eeee76ae2859c10870fd8bd9e60309eb28Chris Forbes        return nullptr;
20585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2059ea8349eeee76ae2859c10870fd8bd9e60309eb28Chris Forbes    return it->second;
20605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
20615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20629a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisRENDER_PASS_STATE *GetRenderPassState(layer_data const *dev_data, VkRenderPass renderpass) {
206351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->renderPassMap.find(renderpass);
206451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->renderPassMap.end()) {
206516387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes        return nullptr;
206616387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes    }
2067fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    return it->second.get();
206816387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes}
206916387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes
20709a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisFRAMEBUFFER_STATE *GetFramebufferState(const layer_data *dev_data, VkFramebuffer framebuffer) {
207151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->frameBufferMap.find(framebuffer);
207251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->frameBufferMap.end()) {
2073f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes        return nullptr;
2074f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes    }
207504861caca7eb93a5241b164e8480bb93c826902cTobin Ehlis    return it->second.get();
2076f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes}
2077f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes
20789a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehliscvdescriptorset::DescriptorSetLayout const *GetDescriptorSetLayout(layer_data const *dev_data, VkDescriptorSetLayout dsLayout) {
207951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->descriptorSetLayoutMap.find(dsLayout);
208051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->descriptorSetLayoutMap.end()) {
208111f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes        return nullptr;
208211f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes    }
208311f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes    return it->second;
208411f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes}
208511f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes
208651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic PIPELINE_LAYOUT_NODE const *getPipelineLayout(layer_data const *dev_data, VkPipelineLayout pipeLayout) {
208751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->pipelineLayoutMap.find(pipeLayout);
208851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->pipelineLayoutMap.end()) {
20894a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes        return nullptr;
20904a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes    }
20914a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes    return &it->second;
20924a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes}
20934a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes
2094e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves// Return true if for a given PSO, the given state enum is dynamic, else return false
20954c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic bool isDynamic(const PIPELINE_STATE *pPipeline, const VkDynamicState state) {
20965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pPipeline && pPipeline->graphicsPipelineCI.pDynamicState) {
20975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < pPipeline->graphicsPipelineCI.pDynamicState->dynamicStateCount; i++) {
2098cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (state == pPipeline->graphicsPipelineCI.pDynamicState->pDynamicStates[i]) return true;
20995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
21005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2101e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    return false;
21025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
21035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
21045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Validate state stored as flags at time of draw call
21054f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayesstatic bool validate_draw_state_flags(layer_data *dev_data, GLOBAL_CB_NODE *pCB, const PIPELINE_STATE *pPipe, bool indexed,
21064f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                      UNIQUE_VALIDATION_ERROR_CODE const msg_code) {
21079c4006684a13db43f0dbc8d0015a9ef34872ca09Chris Forbes    bool result = false;
2108ca546210846c65808717f8875deae39bd227c240Tobin Ehlis    if (pPipe->graphicsPipelineCI.pInputAssemblyState &&
2109ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        ((pPipe->graphicsPipelineCI.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST) ||
2110ca546210846c65808717f8875deae39bd227c240Tobin Ehlis         (pPipe->graphicsPipelineCI.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP))) {
21113d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_LINE_WIDTH_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
21124f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic line width state not set for this command buffer", msg_code);
21133d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
211445824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves    if (pPipe->graphicsPipelineCI.pRasterizationState &&
211545824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves        (pPipe->graphicsPipelineCI.pRasterizationState->depthBiasEnable == VK_TRUE)) {
21163d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_DEPTH_BIAS_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
21174f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic depth bias state not set for this command buffer", msg_code);
21183d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
21193d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    if (pPipe->blendConstantsEnabled) {
21203d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_BLEND_CONSTANTS_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
21214f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic blend constants state not set for this command buffer", msg_code);
21223d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
212345824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves    if (pPipe->graphicsPipelineCI.pDepthStencilState &&
212445824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves        (pPipe->graphicsPipelineCI.pDepthStencilState->depthBoundsTestEnable == VK_TRUE)) {
21253d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_DEPTH_BOUNDS_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
21264f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic depth bounds state not set for this command buffer", msg_code);
21273d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
212845824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves    if (pPipe->graphicsPipelineCI.pDepthStencilState &&
212945824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves        (pPipe->graphicsPipelineCI.pDepthStencilState->stencilTestEnable == VK_TRUE)) {
21303d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_STENCIL_READ_MASK_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
21314f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic stencil read mask state not set for this command buffer", msg_code);
21323d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_STENCIL_WRITE_MASK_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
21334f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic stencil write mask state not set for this command buffer", msg_code);
21343d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_STENCIL_REFERENCE_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
21354f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic stencil reference state not set for this command buffer", msg_code);
21363d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
21371c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    if (indexed) {
21383d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_INDEX_BUFFER_BOUND, VK_DEBUG_REPORT_ERROR_BIT_EXT,
21394f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Index buffer object not bound to this command buffer when Indexed Draw attempted", msg_code);
21403d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
21414f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes
21425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
21435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
21445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
21455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Verify attachment reference compatibility according to spec
21465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  If one array is larger, treat missing elements of shorter array as VK_ATTACHMENT_UNUSED & other array much match this
21475ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski//  If both AttachmentReference arrays have requested index, check their corresponding AttachmentDescriptions
21485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//   to make sure that format and samples counts match.
21495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  If not, they are not compatible.
21505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic bool attachment_references_compatible(const uint32_t index, const VkAttachmentReference *pPrimary,
21515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                             const uint32_t primaryCount, const VkAttachmentDescription *pPrimaryAttachments,
21525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                             const VkAttachmentReference *pSecondary, const uint32_t secondaryCount,
21535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                             const VkAttachmentDescription *pSecondaryAttachments) {
2154e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis    // Check potential NULL cases first to avoid nullptr issues later
2155e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis    if (pPrimary == nullptr) {
2156e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis        if (pSecondary == nullptr) {
2157e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis            return true;
2158e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis        }
2159e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis        return false;
2160e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis    } else if (pSecondary == nullptr) {
2161e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis        return false;
2162e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis    }
2163cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (index >= primaryCount) {  // Check secondary as if primary is VK_ATTACHMENT_UNUSED
2164cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (VK_ATTACHMENT_UNUSED == pSecondary[index].attachment) return true;
2165cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    } else if (index >= secondaryCount) {  // Check primary as if secondary is VK_ATTACHMENT_UNUSED
2166cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (VK_ATTACHMENT_UNUSED == pPrimary[index].attachment) return true;
2167cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    } else {  // Format and sample count must match
21685ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski        if ((pPrimary[index].attachment == VK_ATTACHMENT_UNUSED) && (pSecondary[index].attachment == VK_ATTACHMENT_UNUSED)) {
21695ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski            return true;
21705ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski        } else if ((pPrimary[index].attachment == VK_ATTACHMENT_UNUSED) || (pSecondary[index].attachment == VK_ATTACHMENT_UNUSED)) {
21715ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski            return false;
21725ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski        }
21735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if ((pPrimaryAttachments[pPrimary[index].attachment].format ==
21745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis             pSecondaryAttachments[pSecondary[index].attachment].format) &&
21755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            (pPrimaryAttachments[pPrimary[index].attachment].samples ==
21765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis             pSecondaryAttachments[pSecondary[index].attachment].samples))
21775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return true;
21785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
21795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Format and sample counts didn't match
21805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return false;
21815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
2182a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis// TODO : Scrub verify_renderpass_compatibility() and validateRenderPassCompatibility() and unify them and/or share code
21838da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis// For given primary RenderPass object and secondry RenderPassCreateInfo, verify that they're compatible
218451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool verify_renderpass_compatibility(const layer_data *dev_data, const VkRenderPassCreateInfo *primaryRPCI,
21858da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis                                            const VkRenderPassCreateInfo *secondaryRPCI, string &errorMsg) {
21865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (primaryRPCI->subpassCount != secondaryRPCI->subpassCount) {
2187c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes        stringstream errorStr;
21885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        errorStr << "RenderPass for primary cmdBuffer has " << primaryRPCI->subpassCount
21895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                 << " subpasses but renderPass for secondary cmdBuffer has " << secondaryRPCI->subpassCount << " subpasses.";
21905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        errorMsg = errorStr.str();
21915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return false;
21925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
21935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t spIndex = 0;
21945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (spIndex = 0; spIndex < primaryRPCI->subpassCount; ++spIndex) {
21955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // For each subpass, verify that corresponding color, input, resolve & depth/stencil attachment references are compatible
21965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primaryColorCount = primaryRPCI->pSubpasses[spIndex].colorAttachmentCount;
21975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t secondaryColorCount = secondaryRPCI->pSubpasses[spIndex].colorAttachmentCount;
21985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t colorMax = std::max(primaryColorCount, secondaryColorCount);
21995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t cIdx = 0; cIdx < colorMax; ++cIdx) {
22005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!attachment_references_compatible(cIdx, primaryRPCI->pSubpasses[spIndex].pColorAttachments, primaryColorCount,
22015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                  primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pColorAttachments,
22025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                  secondaryColorCount, secondaryRPCI->pAttachments)) {
2203c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes                stringstream errorStr;
22045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorStr << "color attachments at index " << cIdx << " of subpass index " << spIndex << " are not compatible.";
22055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorMsg = errorStr.str();
22065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return false;
22075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else if (!attachment_references_compatible(cIdx, primaryRPCI->pSubpasses[spIndex].pResolveAttachments,
22085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                         primaryColorCount, primaryRPCI->pAttachments,
22095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                         secondaryRPCI->pSubpasses[spIndex].pResolveAttachments,
22105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                         secondaryColorCount, secondaryRPCI->pAttachments)) {
2211c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes                stringstream errorStr;
22125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorStr << "resolve attachments at index " << cIdx << " of subpass index " << spIndex << " are not compatible.";
22135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorMsg = errorStr.str();
22145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return false;
22155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
22165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
2217fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes
2218bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        if (!attachment_references_compatible(0, primaryRPCI->pSubpasses[spIndex].pDepthStencilAttachment, 1,
2219bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pDepthStencilAttachment,
2220fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes                                              1, secondaryRPCI->pAttachments)) {
2221c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes            stringstream errorStr;
2222fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes            errorStr << "depth/stencil attachments of subpass index " << spIndex << " are not compatible.";
2223fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes            errorMsg = errorStr.str();
2224fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes            return false;
2225fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes        }
2226fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes
22275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primaryInputCount = primaryRPCI->pSubpasses[spIndex].inputAttachmentCount;
22285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t secondaryInputCount = secondaryRPCI->pSubpasses[spIndex].inputAttachmentCount;
22295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t inputMax = std::max(primaryInputCount, secondaryInputCount);
22305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < inputMax; ++i) {
22315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!attachment_references_compatible(i, primaryRPCI->pSubpasses[spIndex].pInputAttachments, primaryColorCount,
22325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                  primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pInputAttachments,
22335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                  secondaryColorCount, secondaryRPCI->pAttachments)) {
2234c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes                stringstream errorStr;
22355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorStr << "input attachments at index " << i << " of subpass index " << spIndex << " are not compatible.";
22365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorMsg = errorStr.str();
22375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return false;
22385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
22395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
22405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
22415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return true;
22425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
22435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2244397d27da37095073c8b86f9ff5289d0a39ce486eTobin Ehlis// For given cvdescriptorset::DescriptorSet, verify that its Set is compatible w/ the setLayout corresponding to
2245397d27da37095073c8b86f9ff5289d0a39ce486eTobin Ehlis// pipelineLayout[layoutIndex]
224651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool verify_set_layout_compatibility(layer_data *dev_data, const cvdescriptorset::DescriptorSet *descriptor_set,
224769b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                                            PIPELINE_LAYOUT_NODE const *pipeline_layout, const uint32_t layoutIndex,
224869b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                                            string &errorMsg) {
2249416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis    auto num_sets = pipeline_layout->set_layouts.size();
22509b5d124aff50234cb0450e1b805baef577c90d83Tobin Ehlis    if (layoutIndex >= num_sets) {
2251c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes        stringstream errorStr;
225269b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis        errorStr << "VkPipelineLayout (" << pipeline_layout->layout << ") only contains " << num_sets
225369b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                 << " setLayouts corresponding to sets 0-" << num_sets - 1 << ", but you're attempting to bind set to index "
225469b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                 << layoutIndex;
22555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        errorMsg = errorStr.str();
22565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return false;
22575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2258416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis    auto layout_node = pipeline_layout->set_layouts[layoutIndex];
22591c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    return descriptor_set->IsCompatible(layout_node, &errorMsg);
22605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
22615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
22625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Validate that data for each specialization entry is fully contained within the buffer.
2263edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_specialization_offsets(debug_report_data *report_data, VkPipelineShaderStageCreateInfo const *info) {
2264e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool pass = true;
22655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
22665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkSpecializationInfo const *spec = info->pSpecializationInfo;
22675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
22685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (spec) {
22695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto i = 0u; i < spec->mapEntryCount; i++) {
22704f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes            // TODO: This is a good place for VALIDATION_ERROR_00589.
22715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (spec->pMapEntries[i].offset + spec->pMapEntries[i].size > spec->dataSize) {
22724f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
22734f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                            VALIDATION_ERROR_00590, "SC",
22745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                            "Specialization entry %u (for constant id %u) references memory outside provided "
22755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                            "specialization data (bytes %u.." PRINTF_SIZE_T_SPECIFIER "; " PRINTF_SIZE_T_SPECIFIER
22764f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                            " bytes provided). %s.",
22775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                            i, spec->pMapEntries[i].constantID, spec->pMapEntries[i].offset,
22784f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                            spec->pMapEntries[i].offset + spec->pMapEntries[i].size - 1, spec->dataSize,
22794f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                            validation_error_map[VALIDATION_ERROR_00590])) {
2280e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                    pass = false;
22815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
22825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
22835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
22845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
22855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
22865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return pass;
22875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
22885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2289bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool descriptor_type_match(shader_module const *module, uint32_t type_id, VkDescriptorType descriptor_type,
2290bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                  unsigned &descriptor_count) {
22915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto type = module->get_def(type_id);
22925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
22931b8c581791ac3c05d7829e04a2d8ecb964b8f2a6Chris Forbes    descriptor_count = 1;
22941b8c581791ac3c05d7829e04a2d8ecb964b8f2a6Chris Forbes
229525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Strip off any array or ptrs. Where we remove array levels, adjust the  descriptor count for each dimension.
22965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while (type.opcode() == spv::OpTypeArray || type.opcode() == spv::OpTypePointer) {
22977b892d2fc502b57d26dc9bff61b0f23cccc595fdChris Forbes        if (type.opcode() == spv::OpTypeArray) {
22987b892d2fc502b57d26dc9bff61b0f23cccc595fdChris Forbes            descriptor_count *= get_constant_value(module, type.word(3));
22997b892d2fc502b57d26dc9bff61b0f23cccc595fdChris Forbes            type = module->get_def(type.word(2));
2300bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        } else {
23017b892d2fc502b57d26dc9bff61b0f23cccc595fdChris Forbes            type = module->get_def(type.word(3));
23027b892d2fc502b57d26dc9bff61b0f23cccc595fdChris Forbes        }
23035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
23045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
23055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (type.opcode()) {
2306cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeStruct: {
2307cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            for (auto insn : *module) {
2308cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (insn.opcode() == spv::OpDecorate && insn.word(1) == type.word(1)) {
2309cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    if (insn.word(2) == spv::DecorationBlock) {
2310cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ||
2311cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                               descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
2312cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    } else if (insn.word(2) == spv::DecorationBufferBlock) {
2313cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ||
2314cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                               descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
2315cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    }
23165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
23175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
23185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2319cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Invalid
2320cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return false;
2321cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
23225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2323cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeSampler:
2324cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return descriptor_type == VK_DESCRIPTOR_TYPE_SAMPLER || descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
23255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2326cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeSampledImage:
2327cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) {
2328cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // Slight relaxation for some GLSL historical madness: samplerBuffer doesn't really have a sampler, and a texel
2329cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // buffer descriptor doesn't really provide one. Allow this slight mismatch.
2330cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto image_type = module->get_def(type.word(2));
2331cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto dim = image_type.word(3);
2332cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto sampled = image_type.word(7);
2333cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return dim == spv::DimBuffer && sampled == 1;
2334cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
2335cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
23365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2337cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeImage: {
2338cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Many descriptor types backing image types-- depends on dimension and whether the image will be used with a sampler.
2339cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // SPIRV for Vulkan requires that sampled be 1 or 2 -- leaving the decision to runtime is unacceptable.
2340cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            auto dim = type.word(3);
2341cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            auto sampled = type.word(7);
23425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2343cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (dim == spv::DimSubpassData) {
2344cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return descriptor_type == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
2345cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else if (dim == spv::DimBuffer) {
2346cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (sampled == 1) {
2347cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    return descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
2348cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                } else {
2349cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
2350cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
2351cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else if (sampled == 1) {
2352cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return descriptor_type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ||
2353cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                       descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
23545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else {
2355cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
23565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
23575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
23585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2359cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        // We shouldn't really see any other junk types -- but if we do, they're a mismatch.
2360cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
2361cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return false;  // Mismatch
23625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
23635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
23645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
23654110a6be7a8a287d459475926985f71c27d01298Chris Forbesstatic bool require_feature(debug_report_data *report_data, VkBool32 feature, char const *feature_name) {
2366a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    if (!feature) {
2367bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
2368cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    SHADER_CHECKER_FEATURE_NOT_ENABLED, "SC",
2369cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "Shader requires VkPhysicalDeviceFeatures::%s but is not "
2370cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "enabled on the device",
2371a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes                    feature_name)) {
2372a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes            return false;
2373a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes        }
2374a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    }
2375a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2376a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    return true;
2377a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes}
2378a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
237969f9a551bfb1fd5334950f9685c12c5adda23dfbChris Forbesstatic bool validate_shader_capabilities(debug_report_data *report_data, shader_module const *src,
238069f9a551bfb1fd5334950f9685c12c5adda23dfbChris Forbes                                         VkPhysicalDeviceFeatures const *enabledFeatures) {
2381e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool pass = true;
2382a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2383a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    for (auto insn : *src) {
2384a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes        if (insn.opcode() == spv::OpCapability) {
2385a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes            switch (insn.word(1)) {
2386cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityMatrix:
2387cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityShader:
2388cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityInputAttachment:
2389cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilitySampled1D:
2390cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityImage1D:
2391cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilitySampledBuffer:
2392cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityImageBuffer:
2393cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityImageQuery:
2394cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityDerivativeControl:
2395cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    // Always supported by a Vulkan 1.0 implementation -- no feature bits.
2396cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2397a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2398cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityGeometry:
2399cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->geometryShader, "geometryShader");
2400cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2401a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2402cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityTessellation:
2403cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->tessellationShader, "tessellationShader");
2404cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2405a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2406cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityFloat64:
2407cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderFloat64, "shaderFloat64");
2408cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2409a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2410cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityInt64:
2411cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderInt64, "shaderInt64");
2412cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2413a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2414cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityTessellationPointSize:
2415cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityGeometryPointSize:
2416cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderTessellationAndGeometryPointSize,
2417cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderTessellationAndGeometryPointSize");
2418cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2419a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2420cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityImageGatherExtended:
2421cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderImageGatherExtended, "shaderImageGatherExtended");
2422cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2423a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2424cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityStorageImageMultisample:
2425cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderStorageImageMultisample,
2426cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderStorageImageMultisample");
2427cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2428a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2429cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityUniformBufferArrayDynamicIndexing:
2430cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderUniformBufferArrayDynamicIndexing,
2431cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderUniformBufferArrayDynamicIndexing");
2432cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2433a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2434cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilitySampledImageArrayDynamicIndexing:
2435cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderSampledImageArrayDynamicIndexing,
2436cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderSampledImageArrayDynamicIndexing");
2437cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2438a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2439cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityStorageBufferArrayDynamicIndexing:
2440cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderStorageBufferArrayDynamicIndexing,
2441cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderStorageBufferArrayDynamicIndexing");
2442cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2443a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2444cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityStorageImageArrayDynamicIndexing:
2445cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderStorageImageArrayDynamicIndexing,
2446cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderStorageImageArrayDynamicIndexing");
2447cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2448a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2449cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityClipDistance:
2450cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderClipDistance, "shaderClipDistance");
2451cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2452a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2453cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityCullDistance:
2454cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderCullDistance, "shaderCullDistance");
2455cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2456a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2457cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityImageCubeArray:
2458cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->imageCubeArray, "imageCubeArray");
2459cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2460a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2461cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilitySampleRateShading:
2462cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->sampleRateShading, "sampleRateShading");
2463cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2464a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2465cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilitySparseResidency:
2466cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderResourceResidency, "shaderResourceResidency");
2467cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2468a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2469cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityMinLod:
2470cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderResourceMinLod, "shaderResourceMinLod");
2471cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2472a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2473cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilitySampledCubeArray:
2474cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->imageCubeArray, "imageCubeArray");
2475cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2476a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2477cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityImageMSArray:
2478cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderStorageImageMultisample,
2479cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderStorageImageMultisample");
2480cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2481a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2482cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityStorageImageExtendedFormats:
2483cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderStorageImageExtendedFormats,
2484cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderStorageImageExtendedFormats");
2485cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2486a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2487cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityInterpolationFunction:
2488cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->sampleRateShading, "sampleRateShading");
2489cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2490a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2491cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityStorageImageReadWithoutFormat:
2492cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderStorageImageReadWithoutFormat,
2493cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderStorageImageReadWithoutFormat");
2494cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2495a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2496cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityStorageImageWriteWithoutFormat:
2497cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderStorageImageWriteWithoutFormat,
2498cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderStorageImageWriteWithoutFormat");
2499cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2500a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2501cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityMultiViewport:
2502cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->multiViewport, "multiViewport");
2503cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2504a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2505cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                default:
2506cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
2507cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                SHADER_CHECKER_BAD_CAPABILITY, "SC", "Shader declares capability %u, not supported in Vulkan.",
2508cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                insn.word(1)))
2509cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        pass = false;
2510cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2511a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes            }
2512a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes        }
2513a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    }
2514a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2515a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    return pass;
2516a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes}
2517a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2518b2a61f3cd17c68887759817059fa1872f1e1464aChris Forbesstatic uint32_t descriptor_type_to_reqs(shader_module const *module, uint32_t type_id) {
25192aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes    auto type = module->get_def(type_id);
25202aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes
25212aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes    while (true) {
25222aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes        switch (type.opcode()) {
2523cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeArray:
2524cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeSampledImage:
2525cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                type = module->get_def(type.word(2));
2526cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
2527cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypePointer:
2528cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                type = module->get_def(type.word(3));
2529cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
2530cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeImage: {
2531cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto dim = type.word(3);
2532cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto arrayed = type.word(5);
2533cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto msaa = type.word(6);
2534cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski
2535cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                switch (dim) {
2536cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    case spv::Dim1D:
2537cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return arrayed ? DESCRIPTOR_REQ_VIEW_TYPE_1D_ARRAY : DESCRIPTOR_REQ_VIEW_TYPE_1D;
2538cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    case spv::Dim2D:
2539cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return (msaa ? DESCRIPTOR_REQ_MULTI_SAMPLE : DESCRIPTOR_REQ_SINGLE_SAMPLE) |
2540cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                               (arrayed ? DESCRIPTOR_REQ_VIEW_TYPE_2D_ARRAY : DESCRIPTOR_REQ_VIEW_TYPE_2D);
2541cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    case spv::Dim3D:
2542cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return DESCRIPTOR_REQ_VIEW_TYPE_3D;
2543cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    case spv::DimCube:
2544cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return arrayed ? DESCRIPTOR_REQ_VIEW_TYPE_CUBE_ARRAY : DESCRIPTOR_REQ_VIEW_TYPE_CUBE;
2545cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    case spv::DimSubpassData:
2546cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return msaa ? DESCRIPTOR_REQ_MULTI_SAMPLE : DESCRIPTOR_REQ_SINGLE_SAMPLE;
2547cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    default:  // buffer, etc.
2548cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return 0;
2549cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
25502aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes            }
2551cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
2552cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return 0;
25532aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes        }
25542aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes    }
2555b2a61f3cd17c68887759817059fa1872f1e1464aChris Forbes}
2556b2a61f3cd17c68887759817059fa1872f1e1464aChris Forbes
2557cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskistatic bool validate_pipeline_shader_stage(
2558cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    debug_report_data *report_data, VkPipelineShaderStageCreateInfo const *pStage, PIPELINE_STATE *pipeline,
2559cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    shader_module **out_module, spirv_inst_iter *out_entrypoint, VkPhysicalDeviceFeatures const *enabledFeatures,
2560cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    std::unordered_map<VkShaderModule, std::unique_ptr<shader_module>> const &shaderModuleMap) {
2561e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool pass = true;
256269f9a551bfb1fd5334950f9685c12c5adda23dfbChris Forbes    auto module_it = shaderModuleMap.find(pStage->module);
256369f9a551bfb1fd5334950f9685c12c5adda23dfbChris Forbes    auto module = *out_module = module_it->second.get();
256478be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
2565c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski    if (!module->has_valid_spirv) return pass;
2566c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski
256725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Find the entrypoint
256878be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    auto entrypoint = *out_entrypoint = find_entrypoint(module, pStage->pName, pStage->stage);
256978be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    if (entrypoint == module->end()) {
25704f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes        if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__, VALIDATION_ERROR_00510,
25714f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                    "SC", "No entrypoint found named `%s` for stage %s. %s.", pStage->pName,
25724f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                    string_VkShaderStageFlagBits(pStage->stage), validation_error_map[VALIDATION_ERROR_00510])) {
2573cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return false;  // no point continuing beyond here, any analysis is just going to be garbage.
257478be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        }
257578be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    }
257678be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
257725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Validate shader capabilities against enabled device features
2578557cdd5218accf51ca894a14b7c6eeeb733f5cbbChris Forbes    pass &= validate_shader_capabilities(report_data, module, enabledFeatures);
257978be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
258025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Mark accessible ids
25813a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    auto accessible_ids = mark_accessible_ids(module, entrypoint);
258278be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
258325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Validate descriptor set layout against what the entrypoint actually uses
25843a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    auto descriptor_uses = collect_interface_by_descriptor_slot(report_data, module, accessible_ids);
258578be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
25862e0eca3d6fad72a29ae072e3895e29a2d2d66476Tobin Ehlis    auto pipelineLayout = pipeline->pipeline_layout;
2587ed399f66e0512ef077d0e0a7cb903248726d2424Chris Forbes
25880cfa9c3a1747749777581684536218f83c3977a9Chris Forbes    pass &= validate_specialization_offsets(report_data, pStage);
2589416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis    pass &= validate_push_constant_usage(report_data, &pipelineLayout.push_constant_ranges, module, accessible_ids, pStage->stage);
259078be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
259125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Validate descriptor use
259278be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    for (auto use : descriptor_uses) {
259378be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        // While validating shaders capture which slots are used by the pipeline
2594bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto &reqs = pipeline->active_slots[use.first.first][use.first.second];
2595b2a61f3cd17c68887759817059fa1872f1e1464aChris Forbes        reqs = descriptor_req(reqs | descriptor_type_to_reqs(module, use.second.type_id));
259678be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
259725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Verify given pipelineLayout has requested setLayout with requested binding
2598c8268861aaa8f9c47920065d6323e4609e5081b0Tobin Ehlis        const auto &binding = get_descriptor_binding(&pipelineLayout, use.first);
259978be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        unsigned required_descriptor_count;
260078be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
260178be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        if (!binding) {
2602bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
2603bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        SHADER_CHECKER_MISSING_DESCRIPTOR, "SC",
260478be5018e238bd464b1f1c55138df277c0c18922Chris Forbes                        "Shader uses descriptor slot %u.%u (used as type `%s`) but not declared in pipeline layout",
260578be5018e238bd464b1f1c55138df277c0c18922Chris Forbes                        use.first.first, use.first.second, describe_type(module, use.second.type_id).c_str())) {
2606e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                pass = false;
260778be5018e238bd464b1f1c55138df277c0c18922Chris Forbes            }
260878be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        } else if (~binding->stageFlags & pStage->stage) {
2609bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
2610cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        SHADER_CHECKER_DESCRIPTOR_NOT_ACCESSIBLE_FROM_STAGE, "SC",
2611cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "Shader uses descriptor slot %u.%u (used "
2612cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "as type `%s`) but descriptor not "
2613cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "accessible from stage %s",
2614fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis                        use.first.first, use.first.second, describe_type(module, use.second.type_id).c_str(),
261578be5018e238bd464b1f1c55138df277c0c18922Chris Forbes                        string_VkShaderStageFlagBits(pStage->stage))) {
2616e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                pass = false;
261778be5018e238bd464b1f1c55138df277c0c18922Chris Forbes            }
2618bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        } else if (!descriptor_type_match(module, use.second.type_id, binding->descriptorType, required_descriptor_count)) {
2619557cdd5218accf51ca894a14b7c6eeeb733f5cbbChris Forbes            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
2620cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        SHADER_CHECKER_DESCRIPTOR_TYPE_MISMATCH, "SC",
2621cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "Type mismatch on descriptor slot "
2622cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "%u.%u (used as type `%s`) but "
2623cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "descriptor of type %s",
2624fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis                        use.first.first, use.first.second, describe_type(module, use.second.type_id).c_str(),
262578be5018e238bd464b1f1c55138df277c0c18922Chris Forbes                        string_VkDescriptorType(binding->descriptorType))) {
2626e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                pass = false;
262778be5018e238bd464b1f1c55138df277c0c18922Chris Forbes            }
262878be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        } else if (binding->descriptorCount < required_descriptor_count) {
2629557cdd5218accf51ca894a14b7c6eeeb733f5cbbChris Forbes            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
2630fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis                        SHADER_CHECKER_DESCRIPTOR_TYPE_MISMATCH, "SC",
263178be5018e238bd464b1f1c55138df277c0c18922Chris Forbes                        "Shader expects at least %u descriptors for binding %u.%u (used as type `%s`) but only %u provided",
263278be5018e238bd464b1f1c55138df277c0c18922Chris Forbes                        required_descriptor_count, use.first.first, use.first.second,
2633fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis                        describe_type(module, use.second.type_id).c_str(), binding->descriptorCount)) {
2634e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                pass = false;
263578be5018e238bd464b1f1c55138df277c0c18922Chris Forbes            }
263678be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        }
263778be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    }
263878be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
263925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Validate use of input attachments against subpass structure
2640c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes    if (pStage->stage == VK_SHADER_STAGE_FRAGMENT_BIT) {
26413a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes        auto input_attachment_uses = collect_interface_by_input_attachment_index(report_data, module, accessible_ids);
2642c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes
2643c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes        auto rpci = pipeline->render_pass_ci.ptr();
2644c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes        auto subpass = pipeline->graphicsPipelineCI.subpass;
2645c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes
2646c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes        for (auto use : input_attachment_uses) {
2647c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes            auto input_attachments = rpci->pSubpasses[subpass].pInputAttachments;
2648bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            auto index = (input_attachments && use.first < rpci->pSubpasses[subpass].inputAttachmentCount)
2649bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             ? input_attachments[use.first].attachment
2650bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             : VK_ATTACHMENT_UNUSED;
2651c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes
2652c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes            if (index == VK_ATTACHMENT_UNUSED) {
2653c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
2654c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes                            SHADER_CHECKER_MISSING_INPUT_ATTACHMENT, "SC",
2655bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "Shader consumes input attachment index %d but not provided in subpass", use.first)) {
2656c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes                    pass = false;
2657c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes                }
2658bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            } else if (get_format_type(rpci->pAttachments[index].format) != get_fundamental_type(module, use.second.type_id)) {
2659eeb9f6a27f1acc11e54080fb3bcda7b513b5c89fChris Forbes                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
2660eeb9f6a27f1acc11e54080fb3bcda7b513b5c89fChris Forbes                            SHADER_CHECKER_INPUT_ATTACHMENT_TYPE_MISMATCH, "SC",
2661bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "Subpass input attachment %u format of %s does not match type used in shader `%s`", use.first,
2662bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            string_VkFormat(rpci->pAttachments[index].format), describe_type(module, use.second.type_id).c_str())) {
2663eeb9f6a27f1acc11e54080fb3bcda7b513b5c89fChris Forbes                    pass = false;
2664eeb9f6a27f1acc11e54080fb3bcda7b513b5c89fChris Forbes                }
2665eeb9f6a27f1acc11e54080fb3bcda7b513b5c89fChris Forbes            }
2666c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes        }
2667c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes    }
2668c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes
266978be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    return pass;
267078be5018e238bd464b1f1c55138df277c0c18922Chris Forbes}
267178be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
2672a61b537fcb6a4f7b92cd217b3964ad7a48109da1Tobin Ehlis// Validate that the shaders used by the given pipeline and store the active_slots
2673a61b537fcb6a4f7b92cd217b3964ad7a48109da1Tobin Ehlis//  that are actually used by the pipeline into pPipeline->active_slots
2674cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskistatic bool validate_and_capture_pipeline_shader_state(
2675cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    debug_report_data *report_data, PIPELINE_STATE *pPipeline, VkPhysicalDeviceFeatures const *enabledFeatures,
2676cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    std::unordered_map<VkShaderModule, unique_ptr<shader_module>> const &shaderModuleMap) {
26776660d6f3e4e4c895063e8d99098162bd2f508b24Chris Forbes    auto pCreateInfo = pPipeline->graphicsPipelineCI.ptr();
26785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    int vertex_stage = get_shader_stage_id(VK_SHADER_STAGE_VERTEX_BIT);
26795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    int fragment_stage = get_shader_stage_id(VK_SHADER_STAGE_FRAGMENT_BIT);
26805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
26815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    shader_module *shaders[5];
26825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    memset(shaders, 0, sizeof(shaders));
26835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter entrypoints[5];
26845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    memset(entrypoints, 0, sizeof(entrypoints));
26855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkPipelineVertexInputStateCreateInfo const *vi = 0;
2686e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool pass = true;
26875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
26885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) {
26896660d6f3e4e4c895063e8d99098162bd2f508b24Chris Forbes        auto pStage = &pCreateInfo->pStages[i];
269078be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        auto stage_id = get_shader_stage_id(pStage->stage);
2691bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pass &= validate_pipeline_shader_stage(report_data, pStage, pPipeline, &shaders[stage_id], &entrypoints[stage_id],
269269f9a551bfb1fd5334950f9685c12c5adda23dfbChris Forbes                                               enabledFeatures, shaderModuleMap);
26935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
26945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2695d5365427feb4a6c16371ecb651afa37b89dabd96Chris Forbes    // if the shader stages are no good individually, cross-stage validation is pointless.
2696cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!pass) return false;
2697b7476f4c4998ae20e579bd2d134667b71acdbf91Chris Forbes
26985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    vi = pCreateInfo->pVertexInputState;
26995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (vi) {
2701e4be8c69231df45752686575f22168b6d0fc5687Chris Forbes        pass &= validate_vi_consistency(report_data, vi);
27025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
27035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2704c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski    if (shaders[vertex_stage] && shaders[vertex_stage]->has_valid_spirv) {
2705e4be8c69231df45752686575f22168b6d0fc5687Chris Forbes        pass &= validate_vi_against_vs_inputs(report_data, vi, shaders[vertex_stage], entrypoints[vertex_stage]);
27065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
27075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    int producer = get_shader_stage_id(VK_SHADER_STAGE_VERTEX_BIT);
27095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    int consumer = get_shader_stage_id(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
27105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while (!shaders[producer] && producer != fragment_stage) {
27125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        producer++;
27135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        consumer++;
27145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
27155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (; producer != fragment_stage && consumer <= fragment_stage; consumer++) {
27175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        assert(shaders[producer]);
2718c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski        if (shaders[consumer] && shaders[consumer]->has_valid_spirv && shaders[producer]->has_valid_spirv) {
2719bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            pass &= validate_interface_between_stages(report_data, shaders[producer], entrypoints[producer],
2720bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      &shader_stage_attribs[producer], shaders[consumer], entrypoints[consumer],
2721bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      &shader_stage_attribs[consumer]);
27225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            producer = consumer;
27245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
27255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
27265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2727c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski    if (shaders[fragment_stage] && shaders[fragment_stage]->has_valid_spirv) {
2728e4be8c69231df45752686575f22168b6d0fc5687Chris Forbes        pass &= validate_fs_outputs_against_render_pass(report_data, shaders[fragment_stage], entrypoints[fragment_stage],
27298da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis                                                        pPipeline->render_pass_ci.ptr(), pCreateInfo->subpass);
27305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
27315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return pass;
27335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
27345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27354c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic bool validate_compute_pipeline(debug_report_data *report_data, PIPELINE_STATE *pPipeline,
27364c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis                                      VkPhysicalDeviceFeatures const *enabledFeatures,
27374c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis                                      std::unordered_map<VkShaderModule, unique_ptr<shader_module>> const &shaderModuleMap) {
27386660d6f3e4e4c895063e8d99098162bd2f508b24Chris Forbes    auto pCreateInfo = pPipeline->computePipelineCI.ptr();
273903857e826cdc6e8d814137fb3245596ca1cb7bc7Chris Forbes
274003857e826cdc6e8d814137fb3245596ca1cb7bc7Chris Forbes    shader_module *module;
274103857e826cdc6e8d814137fb3245596ca1cb7bc7Chris Forbes    spirv_inst_iter entrypoint;
274203857e826cdc6e8d814137fb3245596ca1cb7bc7Chris Forbes
2743bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    return validate_pipeline_shader_stage(report_data, &pCreateInfo->stage, pPipeline, &module, &entrypoint, enabledFeatures,
2744bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                          shaderModuleMap);
274503857e826cdc6e8d814137fb3245596ca1cb7bc7Chris Forbes}
27465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Return Set node ptr for specified set or else NULL
27479a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehliscvdescriptorset::DescriptorSet *GetSetNode(const layer_data *dev_data, VkDescriptorSet set) {
274851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto set_it = dev_data->setMap.find(set);
274951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (set_it == dev_data->setMap.end()) {
27505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return NULL;
27515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2752104ab082916e41467ef60baaab7a5a8b2e02c59cTobin Ehlis    return set_it->second;
27535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
27545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2755eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young// For given pipeline, return number of MSAA samples, or one if MSAA disabled
27564c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic VkSampleCountFlagBits getNumSamples(PIPELINE_STATE const *pipe) {
2757ea8349eeee76ae2859c10870fd8bd9e60309eb28Chris Forbes    if (pipe->graphicsPipelineCI.pMultisampleState != NULL &&
2758ea8349eeee76ae2859c10870fd8bd9e60309eb28Chris Forbes        VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO == pipe->graphicsPipelineCI.pMultisampleState->sType) {
2759eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young        return pipe->graphicsPipelineCI.pMultisampleState->rasterizationSamples;
2760eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    }
2761eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    return VK_SAMPLE_COUNT_1_BIT;
2762eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young}
2763eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
2764bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic void list_bits(std::ostream &s, uint32_t bits) {
2765b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes    for (int i = 0; i < 32 && bits; i++) {
2766b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes        if (bits & (1 << i)) {
2767b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            s << i;
2768b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            bits &= ~(1 << i);
2769b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            if (bits) {
2770b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                s << ",";
2771b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            }
2772b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes        }
2773b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes    }
2774b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes}
2775b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes
2776eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young// Validate draw-time state related to the PSO
277751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool ValidatePipelineDrawtimeState(layer_data const *dev_data, LAST_BOUND_STATE const &state, const GLOBAL_CB_NODE *pCB,
27784c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis                                          PIPELINE_STATE const *pPipeline) {
2779eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    bool skip_call = false;
278029d196e071b2dc1db47702085469396f2b956820Chris Forbes
2781d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen    // Verify vertex binding
278229d196e071b2dc1db47702085469396f2b956820Chris Forbes    if (pPipeline->vertexBindingDescriptions.size() > 0) {
278329d196e071b2dc1db47702085469396f2b956820Chris Forbes        for (size_t i = 0; i < pPipeline->vertexBindingDescriptions.size(); i++) {
2784312129ec52e6249aa453e27e6be17a8dab1e98b8Tobin Ehlis            auto vertex_binding = pPipeline->vertexBindingDescriptions[i].binding;
2785312129ec52e6249aa453e27e6be17a8dab1e98b8Tobin Ehlis            if ((pCB->currentDrawData.buffers.size() < (vertex_binding + 1)) ||
2786312129ec52e6249aa453e27e6be17a8dab1e98b8Tobin Ehlis                (pCB->currentDrawData.buffers[vertex_binding] == VK_NULL_HANDLE)) {
2787cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                skip_call |=
278851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
2789cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            DRAWSTATE_VTX_INDEX_OUT_OF_BOUNDS, "DS",
2790cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "The Pipeline State Object (0x%" PRIxLEAST64
2791cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            ") expects that this Command Buffer's vertex binding Index %u "
2792cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "should be set via vkCmdBindVertexBuffers. This is because VkVertexInputBindingDescription struct "
2793cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "at index " PRINTF_SIZE_T_SPECIFIER " of pVertexBindingDescriptions has a binding value of %u.",
2794cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            (uint64_t)state.pipeline_state->pipeline, vertex_binding, i, vertex_binding);
279529d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
279629d196e071b2dc1db47702085469396f2b956820Chris Forbes        }
279729d196e071b2dc1db47702085469396f2b956820Chris Forbes    } else {
279858b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis        if (!pCB->currentDrawData.buffers.empty() && !pCB->vertex_buffer_used) {
279951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0,
28005c288f35b2eab0dab95d18768235fef6ffd69b30Tobin Ehlis                                 0, __LINE__, DRAWSTATE_VTX_INDEX_OUT_OF_BOUNDS, "DS",
2801226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                 "Vertex buffers are bound to command buffer (0x%p"
28025c288f35b2eab0dab95d18768235fef6ffd69b30Tobin Ehlis                                 ") but no vertex buffers are attached to this Pipeline State Object (0x%" PRIxLEAST64 ").",
2803226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                 pCB->commandBuffer, (uint64_t)state.pipeline_state->pipeline);
280429d196e071b2dc1db47702085469396f2b956820Chris Forbes        }
280529d196e071b2dc1db47702085469396f2b956820Chris Forbes    }
280629d196e071b2dc1db47702085469396f2b956820Chris Forbes    // If Viewport or scissors are dynamic, verify that dynamic count matches PSO count.
280729d196e071b2dc1db47702085469396f2b956820Chris Forbes    // Skip check if rasterization is disabled or there is no viewport.
280829d196e071b2dc1db47702085469396f2b956820Chris Forbes    if ((!pPipeline->graphicsPipelineCI.pRasterizationState ||
280929d196e071b2dc1db47702085469396f2b956820Chris Forbes         (pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable == VK_FALSE)) &&
281029d196e071b2dc1db47702085469396f2b956820Chris Forbes        pPipeline->graphicsPipelineCI.pViewportState) {
281129d196e071b2dc1db47702085469396f2b956820Chris Forbes        bool dynViewport = isDynamic(pPipeline, VK_DYNAMIC_STATE_VIEWPORT);
281229d196e071b2dc1db47702085469396f2b956820Chris Forbes        bool dynScissor = isDynamic(pPipeline, VK_DYNAMIC_STATE_SCISSOR);
2813b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes
281429d196e071b2dc1db47702085469396f2b956820Chris Forbes        if (dynViewport) {
2815b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            auto requiredViewportsMask = (1 << pPipeline->graphicsPipelineCI.pViewportState->viewportCount) - 1;
2816b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            auto missingViewportMask = ~pCB->viewportMask & requiredViewportsMask;
2817b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            if (missingViewportMask) {
2818b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                std::stringstream ss;
2819b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                ss << "Dynamic viewport(s) ";
2820b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                list_bits(ss, missingViewportMask);
2821d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen                ss << " are used by pipeline state object, but were not provided via calls to vkCmdSetViewport().";
282251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
2823bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                     __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", "%s", ss.str().c_str());
282429d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
282529d196e071b2dc1db47702085469396f2b956820Chris Forbes        }
2826b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes
282729d196e071b2dc1db47702085469396f2b956820Chris Forbes        if (dynScissor) {
2828b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            auto requiredScissorMask = (1 << pPipeline->graphicsPipelineCI.pViewportState->scissorCount) - 1;
2829b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            auto missingScissorMask = ~pCB->scissorMask & requiredScissorMask;
2830b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            if (missingScissorMask) {
2831b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                std::stringstream ss;
2832b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                ss << "Dynamic scissor(s) ";
2833b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                list_bits(ss, missingScissorMask);
2834d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen                ss << " are used by pipeline state object, but were not provided via calls to vkCmdSetScissor().";
283551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
2836bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                     __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", "%s", ss.str().c_str());
283729d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
283829d196e071b2dc1db47702085469396f2b956820Chris Forbes        }
283929d196e071b2dc1db47702085469396f2b956820Chris Forbes    }
284029d196e071b2dc1db47702085469396f2b956820Chris Forbes
284129d196e071b2dc1db47702085469396f2b956820Chris Forbes    // Verify that any MSAA request in PSO matches sample# in bound FB
284229d196e071b2dc1db47702085469396f2b956820Chris Forbes    // Skip the check if rasterization is disabled.
284329d196e071b2dc1db47702085469396f2b956820Chris Forbes    if (!pPipeline->graphicsPipelineCI.pRasterizationState ||
284429d196e071b2dc1db47702085469396f2b956820Chris Forbes        (pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable == VK_FALSE)) {
284529d196e071b2dc1db47702085469396f2b956820Chris Forbes        VkSampleCountFlagBits pso_num_samples = getNumSamples(pPipeline);
284629d196e071b2dc1db47702085469396f2b956820Chris Forbes        if (pCB->activeRenderPass) {
2847fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes            auto const render_pass_info = pCB->activeRenderPass->createInfo.ptr();
284829d196e071b2dc1db47702085469396f2b956820Chris Forbes            const VkSubpassDescription *subpass_desc = &render_pass_info->pSubpasses[pCB->activeSubpass];
284929d196e071b2dc1db47702085469396f2b956820Chris Forbes            uint32_t i;
285076957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes            unsigned subpass_num_samples = 0;
28510a7ed0466d3d3c6c71be07d66c200482d9a9d073Chris Forbes
285229d196e071b2dc1db47702085469396f2b956820Chris Forbes            for (i = 0; i < subpass_desc->colorAttachmentCount; i++) {
285376957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                auto attachment = subpass_desc->pColorAttachments[i].attachment;
285476957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                if (attachment != VK_ATTACHMENT_UNUSED)
285576957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                    subpass_num_samples |= (unsigned)render_pass_info->pAttachments[attachment].samples;
285629d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
28570a7ed0466d3d3c6c71be07d66c200482d9a9d073Chris Forbes
285876957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes            if (subpass_desc->pDepthStencilAttachment &&
285976957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                subpass_desc->pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
286076957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                auto attachment = subpass_desc->pDepthStencilAttachment->attachment;
286176957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                subpass_num_samples |= (unsigned)render_pass_info->pAttachments[attachment].samples;
286229d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
2863eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
28640dc3fd4e57b8531638781daa01a2fb5d1048a6fbJamie Madill            if (subpass_num_samples && static_cast<unsigned>(pso_num_samples) != subpass_num_samples) {
286529d196e071b2dc1db47702085469396f2b956820Chris Forbes                skip_call |=
286651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2867bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            reinterpret_cast<const uint64_t &>(pPipeline->pipeline), __LINE__, DRAWSTATE_NUM_SAMPLES_MISMATCH, "DS",
2868bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "Num samples mismatch! At draw-time in Pipeline (0x%" PRIxLEAST64
2869bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            ") with %u samples while current RenderPass (0x%" PRIxLEAST64 ") w/ %u samples!",
2870bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            reinterpret_cast<const uint64_t &>(pPipeline->pipeline), pso_num_samples,
2871bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            reinterpret_cast<const uint64_t &>(pCB->activeRenderPass->renderPass), subpass_num_samples);
2872eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young            }
287329d196e071b2dc1db47702085469396f2b956820Chris Forbes        } else {
287451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2875bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 reinterpret_cast<const uint64_t &>(pPipeline->pipeline), __LINE__, DRAWSTATE_NUM_SAMPLES_MISMATCH,
2876bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 "DS", "No active render pass found at draw-time in Pipeline (0x%" PRIxLEAST64 ")!",
287729d196e071b2dc1db47702085469396f2b956820Chris Forbes                                 reinterpret_cast<const uint64_t &>(pPipeline->pipeline));
2878eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young        }
2879eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    }
2880528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis    // Verify that PSO creation renderPass is compatible with active renderPass
2881528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis    if (pCB->activeRenderPass) {
2882528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis        std::string err_string;
2883a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        if ((pCB->activeRenderPass->renderPass != pPipeline->graphicsPipelineCI.renderPass) &&
288451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            !verify_renderpass_compatibility(dev_data, pCB->activeRenderPass->createInfo.ptr(), pPipeline->render_pass_ci.ptr(),
2885528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis                                             err_string)) {
2886528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis            // renderPass that PSO was created with must be compatible with active renderPass that PSO is being used with
2887528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis            skip_call |=
288851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2889528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis                        reinterpret_cast<const uint64_t &>(pPipeline->pipeline), __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE, "DS",
2890cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "At Draw time the active render pass (0x%" PRIxLEAST64
2891cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        ") is incompatible w/ gfx pipeline "
2892528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis                        "(0x%" PRIxLEAST64 ") that was created w/ render pass (0x%" PRIxLEAST64 ") due to: %s",
28936de0e43adfbd3c049252412d998524e7edbd3796Chris Forbes                        reinterpret_cast<uint64_t &>(pCB->activeRenderPass->renderPass),
28946de0e43adfbd3c049252412d998524e7edbd3796Chris Forbes                        reinterpret_cast<uint64_t const &>(pPipeline->pipeline),
2895528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis                        reinterpret_cast<const uint64_t &>(pPipeline->graphicsPipelineCI.renderPass), err_string.c_str());
2896528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis        }
2897c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes
2898c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes        if (pPipeline->graphicsPipelineCI.subpass != pCB->activeSubpass) {
2899c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes            skip_call |=
290051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2901c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes                        reinterpret_cast<uint64_t const &>(pPipeline->pipeline), __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE, "DS",
2902c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes                        "Pipeline was built for subpass %u but used in subpass %u", pPipeline->graphicsPipelineCI.subpass,
2903c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes                        pCB->activeSubpass);
2904c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes        }
2905528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis    }
290629d196e071b2dc1db47702085469396f2b956820Chris Forbes    // TODO : Add more checks here
290729d196e071b2dc1db47702085469396f2b956820Chris Forbes
2908eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    return skip_call;
2909eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young}
2910eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
29115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Validate overall state at the time of a draw call
291251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool ValidateDrawState(layer_data *dev_data, GLOBAL_CB_NODE *cb_node, const bool indexed,
29134f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                              const VkPipelineBindPoint bind_point, const char *function,
29144f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                              UNIQUE_VALIDATION_ERROR_CODE const msg_code) {
2915e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool result = false;
29161c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    auto const &state = cb_node->lastBound[bind_point];
29174c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    PIPELINE_STATE *pPipe = state.pipeline_state;
291822fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis    if (nullptr == pPipe) {
291922fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis        result |= log_msg(
292051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
292122fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis            DRAWSTATE_INVALID_PIPELINE, "DS",
292222fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis            "At Draw/Dispatch time no valid VkPipeline is bound! This is illegal. Please bind one with vkCmdBindPipeline().");
292322fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis        // Early return as any further checks below will be busted w/o a pipeline
2924cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (result) return true;
292522fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis    }
29263d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    // First check flag states
29271c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    if (VK_PIPELINE_BIND_POINT_GRAPHICS == bind_point)
292851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        result = validate_draw_state_flags(dev_data, cb_node, pPipe, indexed, msg_code);
29297a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis
29305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Now complete other state checks
293169b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis    if (VK_NULL_HANDLE != state.pipeline_layout.layout) {
293222fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis        string errorString;
293369b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis        auto pipeline_layout = pPipe->pipeline_layout;
2934169c4506062f06d6676eb4da3c9e0437d1d9d659Chris Forbes
29351c130ea631a82716dc7334de17767536525f2292Tobin Ehlis        for (const auto &set_binding_pair : pPipe->active_slots) {
29361c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            uint32_t setIndex = set_binding_pair.first;
293722fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis            // If valid set is not bound throw an error
293822fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis            if ((state.boundDescriptorSets.size() <= setIndex) || (!state.boundDescriptorSets[setIndex])) {
293951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                result |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
294022fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                                  DRAWSTATE_DESCRIPTOR_SET_NOT_BOUND, "DS",
2941bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                  "VkPipeline 0x%" PRIxLEAST64 " uses set #%u but that set is not bound.",
2942bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                  (uint64_t)pPipe->pipeline, setIndex);
294351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            } else if (!verify_set_layout_compatibility(dev_data, state.boundDescriptorSets[setIndex], &pipeline_layout, setIndex,
294469b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                                                        errorString)) {
294569b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                // Set is bound but not compatible w/ overlapping pipeline_layout from PSO
294671511c5a10533c910bfe62c3bcf58e2a4054e7acTobin Ehlis                VkDescriptorSet setHandle = state.boundDescriptorSets[setIndex]->GetSet();
294722fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                result |=
294851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
294922fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                            (uint64_t)setHandle, __LINE__, DRAWSTATE_PIPELINE_LAYOUTS_INCOMPATIBLE, "DS",
2950414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                            "VkDescriptorSet (0x%" PRIxLEAST64
2951414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                            ") bound as set #%u is not compatible with overlapping VkPipelineLayout 0x%" PRIxLEAST64 " due to: %s",
295269b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                            reinterpret_cast<uint64_t &>(setHandle), setIndex, reinterpret_cast<uint64_t &>(pipeline_layout.layout),
295369b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                            errorString.c_str());
2954cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else {  // Valid set is bound and layout compatible, validate that it's updated
295522fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                // Pull the set node
29561c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                cvdescriptorset::DescriptorSet *descriptor_set = state.boundDescriptorSets[setIndex];
2957aa21bc3b3c5c7adfeb488fc80bdcb339d63615b8Tobin Ehlis                // Gather active bindings
2958ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                std::unordered_set<uint32_t> active_bindings;
29591c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                for (auto binding : set_binding_pair.second) {
2960ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                    active_bindings.insert(binding.first);
2961aa21bc3b3c5c7adfeb488fc80bdcb339d63615b8Tobin Ehlis                }
296222fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                // Make sure set has been updated if it has no immutable samplers
296322fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                //  If it has immutable samplers, we'll flag error later as needed depending on binding
29641c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                if (!descriptor_set->IsUpdated()) {
2965ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                    for (auto binding : active_bindings) {
29661c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                        if (!descriptor_set->GetImmutableSamplerPtrFromBinding(binding)) {
296751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                            result |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
2968cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                              VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)descriptor_set->GetSet(),
2969cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                              __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS",
2970cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                              "Descriptor Set 0x%" PRIxLEAST64
2971cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                              " bound but was never updated. It is now being used to draw so "
2972cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                              "this will result in undefined behavior.",
2973cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                              (uint64_t)descriptor_set->GetSet());
2974fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis                        }
29755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
29765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
29777433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis                // Validate the draw-time state for this descriptor set
29787433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis                std::string err_str;
29791c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                if (!descriptor_set->ValidateDrawState(set_binding_pair.second, state.dynamicOffsets[setIndex], &err_str)) {
29801c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                    auto set = descriptor_set->GetSet();
298151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                    result |= log_msg(
298251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
298351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                        reinterpret_cast<const uint64_t &>(set), __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS",
298451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                        "Descriptor set 0x%" PRIxLEAST64 " encountered the following validation error at %s() time: %s",
298551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                        reinterpret_cast<const uint64_t &>(set), function, err_str.c_str());
29867433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis                }
29875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
298822fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis        }
298922fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis    }
2990eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
2991eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    // Check general pipeline state that needs to be validated at drawtime
299251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (VK_PIPELINE_BIND_POINT_GRAPHICS == bind_point) result |= ValidatePipelineDrawtimeState(dev_data, state, cb_node, pPipe);
2993eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
29945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
29955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
29965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
299751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void UpdateDrawState(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, const VkPipelineBindPoint bind_point) {
29981c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    auto const &state = cb_state->lastBound[bind_point];
2999ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis    PIPELINE_STATE *pPipe = state.pipeline_state;
3000ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis    if (VK_NULL_HANDLE != state.pipeline_layout.layout) {
30011c130ea631a82716dc7334de17767536525f2292Tobin Ehlis        for (const auto &set_binding_pair : pPipe->active_slots) {
30021c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            uint32_t setIndex = set_binding_pair.first;
3003ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis            // Pull the set node
30041c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            cvdescriptorset::DescriptorSet *descriptor_set = state.boundDescriptorSets[setIndex];
3005ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis            // Bind this set and its active descriptor resources to the command buffer
30061c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            descriptor_set->BindCommandBuffer(cb_state, set_binding_pair.second);
30077433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis            // For given active slots record updated images & buffers
30081c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            descriptor_set->GetStorageUpdates(set_binding_pair.second, &cb_state->updateBuffers, &cb_state->updateImages);
3009ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis        }
3010ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis    }
301158b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    if (pPipe->vertexBindingDescriptions.size() > 0) {
301258b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis        cb_state->vertex_buffer_used = true;
301358b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    }
3014ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis}
3015ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis
3016a27508babf63d50aea75883a3702979193c23683Mark Young// Validate HW line width capabilities prior to setting requested line width.
301751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool verifyLineWidth(layer_data *dev_data, DRAW_STATE_ERROR dsError, const uint64_t &target, float lineWidth) {
3018a27508babf63d50aea75883a3702979193c23683Mark Young    bool skip_call = false;
3019a27508babf63d50aea75883a3702979193c23683Mark Young
3020a27508babf63d50aea75883a3702979193c23683Mark Young    // First check to see if the physical device supports wide lines.
302151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if ((VK_FALSE == dev_data->enabled_features.wideLines) && (1.0f != lineWidth)) {
302251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, target, __LINE__,
3023cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             dsError, "DS",
3024cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "Attempt to set lineWidth to %f but physical device wideLines feature "
3025cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "not supported/enabled so lineWidth must be 1.0f!",
3026a27508babf63d50aea75883a3702979193c23683Mark Young                             lineWidth);
3027a27508babf63d50aea75883a3702979193c23683Mark Young    } else {
3028a27508babf63d50aea75883a3702979193c23683Mark Young        // Otherwise, make sure the width falls in the valid range.
302951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        if ((dev_data->phys_dev_properties.properties.limits.lineWidthRange[0] > lineWidth) ||
303051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            (dev_data->phys_dev_properties.properties.limits.lineWidthRange[1] < lineWidth)) {
303151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, target,
3032cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 __LINE__, dsError, "DS",
3033cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "Attempt to set lineWidth to %f but physical device limits line width "
3034cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "to between [%f, %f]!",
303551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                                 lineWidth, dev_data->phys_dev_properties.properties.limits.lineWidthRange[0],
303651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                                 dev_data->phys_dev_properties.properties.limits.lineWidthRange[1]);
3037a27508babf63d50aea75883a3702979193c23683Mark Young        }
3038a27508babf63d50aea75883a3702979193c23683Mark Young    }
3039a27508babf63d50aea75883a3702979193c23683Mark Young
3040a27508babf63d50aea75883a3702979193c23683Mark Young    return skip_call;
3041a27508babf63d50aea75883a3702979193c23683Mark Young}
3042a27508babf63d50aea75883a3702979193c23683Mark Young
30435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Verify that create state for a pipeline is valid
304451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool verifyPipelineCreateState(layer_data *dev_data, std::vector<PIPELINE_STATE *> pPipelines, int pipelineIndex) {
304583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
30465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
30474c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    PIPELINE_STATE *pPipeline = pPipelines[pipelineIndex];
30485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
30495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If create derivative bit is set, check that we've specified a base
30505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // pipeline correctly, and that the base pipeline was created to allow
30515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // derivatives.
30525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pPipeline->graphicsPipelineCI.flags & VK_PIPELINE_CREATE_DERIVATIVE_BIT) {
30534c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis        PIPELINE_STATE *pBasePipeline = nullptr;
30545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!((pPipeline->graphicsPipelineCI.basePipelineHandle != VK_NULL_HANDLE) ^
30555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis              (pPipeline->graphicsPipelineCI.basePipelineIndex != -1))) {
3056f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt            // This check is a superset of VALIDATION_ERROR_00526 and VALIDATION_ERROR_00528
305751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
305883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
305983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 "Invalid Pipeline CreateInfo: exactly one of base pipeline index and handle must be specified");
30605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (pPipeline->graphicsPipelineCI.basePipelineIndex != -1) {
30615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (pPipeline->graphicsPipelineCI.basePipelineIndex >= pipelineIndex) {
306283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                skip_call |=
306351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3064f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                            VALIDATION_ERROR_00518, "DS",
3065f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                            "Invalid Pipeline CreateInfo: base pipeline must occur earlier in array than derivative pipeline. %s",
3066f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                            validation_error_map[VALIDATION_ERROR_00518]);
30675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else {
30685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pBasePipeline = pPipelines[pPipeline->graphicsPipelineCI.basePipelineIndex];
30695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
30705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (pPipeline->graphicsPipelineCI.basePipelineHandle != VK_NULL_HANDLE) {
307151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            pBasePipeline = getPipelineState(dev_data, pPipeline->graphicsPipelineCI.basePipelineHandle);
30725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
30735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
30745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (pBasePipeline && !(pBasePipeline->graphicsPipelineCI.flags & VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT)) {
307551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
307683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
307783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 "Invalid Pipeline CreateInfo: base pipeline does not allow derivatives.");
30785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
30795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
30805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
30815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pPipeline->graphicsPipelineCI.pColorBlendState != NULL) {
3082fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis        const safe_VkPipelineColorBlendStateCreateInfo *color_blend_state = pPipeline->graphicsPipelineCI.pColorBlendState;
30839a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto const render_pass_info = GetRenderPassState(dev_data, pPipeline->graphicsPipelineCI.renderPass)->createInfo.ptr();
3084fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis        const VkSubpassDescription *subpass_desc = &render_pass_info->pSubpasses[pPipeline->graphicsPipelineCI.subpass];
3085fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis        if (color_blend_state->attachmentCount != subpass_desc->colorAttachmentCount) {
3086fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis            skip_call |= log_msg(
308751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
3088fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis                reinterpret_cast<const uint64_t &>(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_02109, "DS",
3089fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis                "vkCreateGraphicsPipelines(): Render pass (0x%" PRIxLEAST64
3090fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis                ") subpass %u has colorAttachmentCount of %u which doesn't match the pColorBlendState->attachmentCount of %u. %s",
3091fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis                reinterpret_cast<const uint64_t &>(pPipeline->graphicsPipelineCI.renderPass), pPipeline->graphicsPipelineCI.subpass,
3092fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis                subpass_desc->colorAttachmentCount, color_blend_state->attachmentCount,
3093fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis                validation_error_map[VALIDATION_ERROR_02109]);
3094fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis        }
309551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        if (!dev_data->enabled_features.independentBlend) {
30963d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis            if (pPipeline->attachments.size() > 1) {
309726c548826ff0f83d12c769b51e7d6f76d1265c0eChris Forbes                VkPipelineColorBlendAttachmentState *pAttachments = &pPipeline->attachments[0];
3098c7bd67f06427b08ba65cdf2dd529c8234beebdd5Mark Lobodzinski                for (size_t i = 1; i < pPipeline->attachments.size(); i++) {
309906811df0256552cd7da9d7297672af377463fc4aMark Mueller                    // Quoting the spec: "If [the independent blend] feature is not enabled, the VkPipelineColorBlendAttachmentState
310006811df0256552cd7da9d7297672af377463fc4aMark Mueller                    // settings for all color attachments must be identical." VkPipelineColorBlendAttachmentState contains
310106811df0256552cd7da9d7297672af377463fc4aMark Mueller                    // only attachment state, so memcmp is best suited for the comparison
310206811df0256552cd7da9d7297672af377463fc4aMark Mueller                    if (memcmp(static_cast<const void *>(pAttachments), static_cast<const void *>(&pAttachments[i]),
310306811df0256552cd7da9d7297672af377463fc4aMark Mueller                               sizeof(pAttachments[0]))) {
310451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
3105cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                             __LINE__, VALIDATION_ERROR_01532, "DS",
3106cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                             "Invalid Pipeline CreateInfo: If independent blend feature not "
3107cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                             "enabled, all elements of pAttachments must be identical. %s",
3108cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                             validation_error_map[VALIDATION_ERROR_01532]);
310906811df0256552cd7da9d7297672af377463fc4aMark Mueller                        break;
3110c7bd67f06427b08ba65cdf2dd529c8234beebdd5Mark Lobodzinski                    }
31115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
31125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
31135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
311451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        if (!dev_data->enabled_features.logicOp && (pPipeline->graphicsPipelineCI.pColorBlendState->logicOpEnable != VK_FALSE)) {
311583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |=
311651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3117f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                        VALIDATION_ERROR_01533, "DS",
3118f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                        "Invalid Pipeline CreateInfo: If logic operations feature not enabled, logicOpEnable must be VK_FALSE. %s",
3119f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                        validation_error_map[VALIDATION_ERROR_01533]);
31205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
31215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
31225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3123a61b537fcb6a4f7b92cd217b3964ad7a48109da1Tobin Ehlis    // Ensure the subpass index is valid. If not, then validate_and_capture_pipeline_shader_state
31245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // produces nonsense errors that confuse users. Other layers should already
31255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // emit errors for renderpass being invalid.
31269a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto renderPass = GetRenderPassState(dev_data, pPipeline->graphicsPipelineCI.renderPass);
3127fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    if (renderPass && pPipeline->graphicsPipelineCI.subpass >= renderPass->createInfo.subpassCount) {
312851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3129cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             VALIDATION_ERROR_02122, "DS",
3130cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "Invalid Pipeline CreateInfo State: Subpass index %u "
3131cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "is out of range for this renderpass (0..%u). %s",
3132f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             pPipeline->graphicsPipelineCI.subpass, renderPass->createInfo.subpassCount - 1,
3133f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             validation_error_map[VALIDATION_ERROR_02122]);
31345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
31355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
313651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (!GetDisables(dev_data)->shader_validation &&
313751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        !validate_and_capture_pipeline_shader_state(dev_data->report_data, pPipeline, &dev_data->enabled_features,
313851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                                                    dev_data->shaderModuleMap)) {
313983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis        skip_call = true;
31405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
314152156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes    // Each shader's stage must be unique
314252156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes    if (pPipeline->duplicate_shaders) {
314352156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes        for (uint32_t stage = VK_SHADER_STAGE_VERTEX_BIT; stage & VK_SHADER_STAGE_ALL_GRAPHICS; stage <<= 1) {
314452156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes            if (pPipeline->duplicate_shaders & stage) {
314551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
314683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                     __LINE__, DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
314783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                     "Invalid Pipeline CreateInfo State: Multiple shaders provided for stage %s",
314883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                     string_VkShaderStageFlagBits(VkShaderStageFlagBits(stage)));
314952156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes            }
315052156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes        }
315152156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes    }
31525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // VS is required
31535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (!(pPipeline->active_shaders & VK_SHADER_STAGE_VERTEX_BIT)) {
315451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3155f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             VALIDATION_ERROR_00532, "DS", "Invalid Pipeline CreateInfo State: Vertex Shader required. %s",
3156f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             validation_error_map[VALIDATION_ERROR_00532]);
31575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
31585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Either both or neither TC/TE shaders should be defined
3159f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    if ((pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) &&
3160f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt        !(pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)) {
316151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3162f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             VALIDATION_ERROR_00534, "DS",
3163f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             "Invalid Pipeline CreateInfo State: TE and TC shaders must be included or excluded as a pair. %s",
3164f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             validation_error_map[VALIDATION_ERROR_00534]);
3165f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    }
3166f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    if (!(pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) &&
3167f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt        (pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)) {
316851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3169f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             VALIDATION_ERROR_00535, "DS",
3170f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             "Invalid Pipeline CreateInfo State: TE and TC shaders must be included or excluded as a pair. %s",
3171f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             validation_error_map[VALIDATION_ERROR_00535]);
31725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
31735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Compute shaders should be specified independent of Gfx shaders
3174f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    if (pPipeline->active_shaders & VK_SHADER_STAGE_COMPUTE_BIT) {
317551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3176f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             VALIDATION_ERROR_00533, "DS",
3177f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             "Invalid Pipeline CreateInfo State: Do not specify Compute Shader for Gfx Pipeline. %s",
3178f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             validation_error_map[VALIDATION_ERROR_00533]);
31795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
31805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive topology is only valid for tessellation pipelines.
31815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Mismatching primitive topology and tessellation fails graphics pipeline creation.
31825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pPipeline->active_shaders & (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) &&
3183ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        (!pPipeline->graphicsPipelineCI.pInputAssemblyState ||
3184ca546210846c65808717f8875deae39bd227c240Tobin Ehlis         pPipeline->graphicsPipelineCI.pInputAssemblyState->topology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST)) {
318551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3186cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             VALIDATION_ERROR_02099, "DS",
3187cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "Invalid Pipeline CreateInfo State: "
3188cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST must be set as IA "
3189cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "topology for tessellation pipelines. %s",
3190f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             validation_error_map[VALIDATION_ERROR_02099]);
31915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
3192ca546210846c65808717f8875deae39bd227c240Tobin Ehlis    if (pPipeline->graphicsPipelineCI.pInputAssemblyState &&
3193ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        pPipeline->graphicsPipelineCI.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) {
31945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (~pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) {
319551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3196cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 VALIDATION_ERROR_02100, "DS",
3197cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "Invalid Pipeline CreateInfo State: "
3198cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive "
3199cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "topology is only valid for tessellation pipelines. %s",
3200f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                                 validation_error_map[VALIDATION_ERROR_02100]);
32015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
32025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
3203f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt
3204f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    if (pPipeline->graphicsPipelineCI.pTessellationState &&
3205f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt        ((pPipeline->graphicsPipelineCI.pTessellationState->patchControlPoints == 0) ||
3206f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt         (pPipeline->graphicsPipelineCI.pTessellationState->patchControlPoints >
320751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis          dev_data->phys_dev_properties.properties.limits.maxTessellationPatchSize))) {
320851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3209cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             VALIDATION_ERROR_01426, "DS",
3210cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "Invalid Pipeline CreateInfo State: "
3211cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive "
3212cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "topology used with patchControlPoints value %u."
3213cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             " patchControlPoints should be >0 and <=%u. %s",
3214f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             pPipeline->graphicsPipelineCI.pTessellationState->patchControlPoints,
321551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                             dev_data->phys_dev_properties.properties.limits.maxTessellationPatchSize,
3216f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             validation_error_map[VALIDATION_ERROR_01426]);
3217f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    }
3218f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt
32196b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen    // If a rasterization state is provided...
3220a27508babf63d50aea75883a3702979193c23683Mark Young    if (pPipeline->graphicsPipelineCI.pRasterizationState) {
32216b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen
32226b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen        // Make sure that the line width conforms to the HW.
3223a27508babf63d50aea75883a3702979193c23683Mark Young        if (!isDynamic(pPipeline, VK_DYNAMIC_STATE_LINE_WIDTH)) {
322451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            skip_call |= verifyLineWidth(dev_data, DRAWSTATE_INVALID_PIPELINE_CREATE_STATE,
32256de0e43adfbd3c049252412d998524e7edbd3796Chris Forbes                                         reinterpret_cast<uint64_t const &>(pPipeline->pipeline),
322683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                         pPipeline->graphicsPipelineCI.pRasterizationState->lineWidth);
3227a27508babf63d50aea75883a3702979193c23683Mark Young        }
32285dcdd90e54199dfeb29938a3a03d998397c22664Chris Forbes
32296b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen        // If rasterization is enabled...
32306b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen        if (pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable == VK_FALSE) {
32316b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen            auto subpass_desc = renderPass ? &renderPass->createInfo.pSubpasses[pPipeline->graphicsPipelineCI.subpass] : nullptr;
32326b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen
32336b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen            // If subpass uses a depth/stencil attachment, pDepthStencilState must be a pointer to a valid structure
32346b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen            if (subpass_desc && subpass_desc->pDepthStencilAttachment &&
32356b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen                subpass_desc->pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
32366b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen                if (!pPipeline->graphicsPipelineCI.pDepthStencilState) {
32376b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
32386b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen                                         VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, VALIDATION_ERROR_02115, "DS",
32396b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen                                         "Invalid Pipeline CreateInfo State: pDepthStencilState is NULL when rasterization is "
32406b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen                                         "enabled and subpass uses a depth/stencil attachment. %s",
32416b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen                                         validation_error_map[VALIDATION_ERROR_02115]);
32426b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen                }
32435dcdd90e54199dfeb29938a3a03d998397c22664Chris Forbes            }
3244326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen
3245326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen            // If subpass uses color attachments, pColorBlendState must be valid pointer
3246326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen            if (subpass_desc) {
3247326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                uint32_t color_attachment_count = 0;
3248326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                for (uint32_t i = 0; i < subpass_desc->colorAttachmentCount; ++i) {
3249326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                    if (subpass_desc->pColorAttachments[i].attachment != VK_ATTACHMENT_UNUSED) {
3250326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                        ++color_attachment_count;
3251326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                    }
3252326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                }
3253326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                if (color_attachment_count > 0 && pPipeline->graphicsPipelineCI.pColorBlendState == nullptr) {
3254326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
3255326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                                         VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, VALIDATION_ERROR_02116, "DS",
3256326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                                         "Invalid Pipeline CreateInfo State: pColorBlendState is NULL when rasterization is "
3257326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                                         "enabled and subpass uses color attachments. %s",
3258326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                                         validation_error_map[VALIDATION_ERROR_02116]);
3259326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                }
3260326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen            }
32615dcdd90e54199dfeb29938a3a03d998397c22664Chris Forbes        }
32625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
32636b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen
326483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
32655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
32665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
32675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Free the Pipeline nodes
326851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void deletePipelines(layer_data *dev_data) {
326951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (dev_data->pipelineMap.size() <= 0) return;
327051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    for (auto &pipe_map_pair : dev_data->pipelineMap) {
3271ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        delete pipe_map_pair.second;
32725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
327351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    dev_data->pipelineMap.clear();
32745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
32755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
32765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Block of code at start here specifically for managing/tracking DSs
32775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
32785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Return Pool node ptr for specified pool or else NULL
32799a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisDESCRIPTOR_POOL_STATE *GetDescriptorPoolState(const layer_data *dev_data, const VkDescriptorPool pool) {
3280bb7ea477706f90eb2a72887f652795bc79f60ddeTobin Ehlis    auto pool_it = dev_data->descriptorPoolMap.find(pool);
3281bb7ea477706f90eb2a72887f652795bc79f60ddeTobin Ehlis    if (pool_it == dev_data->descriptorPoolMap.end()) {
32825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return NULL;
32835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
3284bb7ea477706f90eb2a72887f652795bc79f60ddeTobin Ehlis    return pool_it->second;
32855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
32865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
32875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Validate that given set is valid and that it's not being used by an in-flight CmdBuffer
32885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// func_str is the name of the calling function
3289e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves// Return false if no errors occur
3290e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves// Return true if validation error occurs and callback returns true (to skip upcoming API call down the chain)
32910dcd0f7b37456e2e552d37094ba503c0d089b906Tobin Ehlisstatic bool validateIdleDescriptorSet(const layer_data *dev_data, VkDescriptorSet set, std::string func_str) {
3292cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.idle_descriptor_set) return false;
3293e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
32940dcd0f7b37456e2e552d37094ba503c0d089b906Tobin Ehlis    auto set_node = dev_data->setMap.find(set);
32950dcd0f7b37456e2e552d37094ba503c0d089b906Tobin Ehlis    if (set_node == dev_data->setMap.end()) {
32960dcd0f7b37456e2e552d37094ba503c0d089b906Tobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
32975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                             (uint64_t)(set), __LINE__, DRAWSTATE_DOUBLE_DESTROY, "DS",
3298414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                             "Cannot call %s() on descriptor set 0x%" PRIxLEAST64 " that has not been allocated.", func_str.c_str(),
32995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                             (uint64_t)(set));
33005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
33011c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis        // TODO : This covers various error cases so should pass error enum into this function and use passed in enum here
33025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (set_node->second->in_use.load()) {
33031c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis            skip_call |=
33040dcd0f7b37456e2e552d37094ba503c0d089b906Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
33051c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis                        (uint64_t)(set), __LINE__, VALIDATION_ERROR_00919, "DS",
33061c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis                        "Cannot call %s() on descriptor set 0x%" PRIxLEAST64 " that is in use by a command buffer. %s",
33071c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis                        func_str.c_str(), (uint64_t)(set), validation_error_map[VALIDATION_ERROR_00919]);
33085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
33095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
33105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
33115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
3312f80bf38f4fb3f177b3e1be11b7b1c5edcdbf7d9bChris Forbes
3313e6651096ed8f07840447783c66827cc16d659a49Tobin Ehlis// Remove set from setMap and delete the set
33149dd448578d59cb5ce692e833ba230783b30f3550Tobin Ehlisstatic void freeDescriptorSet(layer_data *dev_data, cvdescriptorset::DescriptorSet *descriptor_set) {
33159dd448578d59cb5ce692e833ba230783b30f3550Tobin Ehlis    dev_data->setMap.erase(descriptor_set->GetSet());
33169dd448578d59cb5ce692e833ba230783b30f3550Tobin Ehlis    delete descriptor_set;
33179dd448578d59cb5ce692e833ba230783b30f3550Tobin Ehlis}
33185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Free all DS Pools including their Sets & related sub-structs
33195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// NOTE : Calls to this function should be wrapped in mutex
332051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void deletePools(layer_data *dev_data) {
332151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (dev_data->descriptorPoolMap.size() <= 0) return;
332251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    for (auto ii = dev_data->descriptorPoolMap.begin(); ii != dev_data->descriptorPoolMap.end(); ++ii) {
3323c5f47f0a54e14c47d402aeabc6498d981ecda9ccTobin Ehlis        // Remove this pools' sets from setMap and delete them
3324cb9ce9e05b8e939d3da35c64997c70049877f4feTobin Ehlis        for (auto ds : (*ii).second->sets) {
332551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            freeDescriptorSet(dev_data, ds);
33265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
3327f13bee0887f3c3d1d597c82869864be3be836737Tobin Ehlis        (*ii).second->sets.clear();
33285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
332951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    dev_data->descriptorPoolMap.clear();
33305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
33315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
333251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void clearDescriptorPool(layer_data *dev_data, const VkDevice device, const VkDescriptorPool pool,
33335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                VkDescriptorPoolResetFlags flags) {
33349a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DESCRIPTOR_POOL_STATE *pPool = GetDescriptorPoolState(dev_data, pool);
3335de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    // TODO: validate flags
3336de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    // For every set off of this pool, clear it, remove from setMap, and free cvdescriptorset::DescriptorSet
3337de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    for (auto ds : pPool->sets) {
333851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        freeDescriptorSet(dev_data, ds);
3339de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    }
3340de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    pPool->sets.clear();
3341de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    // Reset available count for each type and available sets for this pool
3342de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    for (uint32_t i = 0; i < pPool->availableDescriptorTypeCount.size(); ++i) {
3343de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis        pPool->availableDescriptorTypeCount[i] = pPool->maxDescriptorTypeCount[i];
33445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
3345de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    pPool->availableSets = pPool->maxSets;
33465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
33475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
33485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// For given CB object, fetch associated CB Node from map
33499a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisGLOBAL_CB_NODE *GetCBNode(layer_data const *dev_data, const VkCommandBuffer cb) {
335051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->commandBufferMap.find(cb);
335151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->commandBufferMap.end()) {
33525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return NULL;
33535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
33545121a8dcacb23766ba4455b4eea429f0a3d62099Chris Forbes    return it->second;
33555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
33565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Free all CB Nodes
33575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// NOTE : Calls to this function should be wrapped in mutex
335851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void deleteCommandBuffers(layer_data *dev_data) {
335951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (dev_data->commandBufferMap.empty()) {
33605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return;
33615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
336251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    for (auto ii = dev_data->commandBufferMap.begin(); ii != dev_data->commandBufferMap.end(); ++ii) {
33635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        delete (*ii).second;
33645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
336551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    dev_data->commandBufferMap.clear();
33665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
33675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3368e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool report_error_no_cb_begin(const layer_data *dev_data, const VkCommandBuffer cb, const char *caller_name) {
33695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
33705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                   (uint64_t)cb, __LINE__, DRAWSTATE_NO_BEGIN_COMMAND_BUFFER, "DS",
33715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                   "You must call vkBeginCommandBuffer() before this call to %s", caller_name);
33725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
33735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
337429f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis// If a renderpass is active, verify that the given command type is appropriate for current subpass state
337529f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlisbool ValidateCmdSubpassState(const layer_data *dev_data, const GLOBAL_CB_NODE *pCB, const CMD_TYPE cmd_type) {
3376cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!pCB->activeRenderPass) return false;
3377e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
3378d0d8e333806eaac08bdc87ddeff886dc2b0f09e7Tobin Ehlis    if (pCB->activeSubpassContents == VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS &&
3379d0d8e333806eaac08bdc87ddeff886dc2b0f09e7Tobin Ehlis        (cmd_type != CMD_EXECUTECOMMANDS && cmd_type != CMD_NEXTSUBPASS && cmd_type != CMD_ENDRENDERPASS)) {
33805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
33815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                             DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
33825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                             "Commands cannot be called in a subpass using secondary command buffers.");
33835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else if (pCB->activeSubpassContents == VK_SUBPASS_CONTENTS_INLINE && cmd_type == CMD_EXECUTECOMMANDS) {
33845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
33855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                             DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
33865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                             "vkCmdExecuteCommands() cannot be called in a subpass using inline commands.");
33875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
33885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
33895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
33905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
339151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool checkGraphicsBit(const layer_data *dev_data, VkQueueFlags flags, const char *name) {
33925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (!(flags & VK_QUEUE_GRAPHICS_BIT))
339351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
33945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                       DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
33955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                       "Cannot call %s on a command buffer allocated from a pool without graphics capabilities.", name);
33965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return false;
33975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
33985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
339951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool checkComputeBit(const layer_data *dev_data, VkQueueFlags flags, const char *name) {
34005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (!(flags & VK_QUEUE_COMPUTE_BIT))
340151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
34025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                       DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
34035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                       "Cannot call %s on a command buffer allocated from a pool without compute capabilities.", name);
34045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return false;
34055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
34065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
340751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool checkGraphicsOrComputeBit(const layer_data *dev_data, VkQueueFlags flags, const char *name) {
34085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (!((flags & VK_QUEUE_GRAPHICS_BIT) || (flags & VK_QUEUE_COMPUTE_BIT)))
340951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
34105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                       DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
34115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                       "Cannot call %s on a command buffer allocated from a pool without graphics capabilities.", name);
34125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return false;
34135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
34145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3415623784ad78c8b77a78c4db613db974c12e5f5a43Mark Lobodzinski// Validate the given command being added to the specified cmd buffer, flagging errors if CB is not in the recording state or if
3416623784ad78c8b77a78c4db613db974c12e5f5a43Mark Lobodzinski// there's an issue with the Cmd ordering
341751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisbool ValidateCmd(layer_data *dev_data, GLOBAL_CB_NODE *pCB, const CMD_TYPE cmd, const char *caller_name) {
341883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
34199a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pPool = GetCommandPoolNode(dev_data, pCB->createInfo.commandPool);
3420a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes    if (pPool) {
342151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        VkQueueFlags flags = dev_data->phys_dev_properties.queue_family_properties[pPool->queueFamilyIndex].queueFlags;
34225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        switch (cmd) {
3423cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_BINDPIPELINE:
3424cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_BINDPIPELINEDELTA:
3425cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_BINDDESCRIPTORSETS:
3426cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_FILLBUFFER:
3427cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_CLEARCOLORIMAGE:
3428cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_SETEVENT:
3429cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_RESETEVENT:
3430cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_WAITEVENTS:
3431cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_BEGINQUERY:
3432cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_ENDQUERY:
3433cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_RESETQUERYPOOL:
3434cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_COPYQUERYPOOLRESULTS:
3435cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_WRITETIMESTAMP:
343651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                skip_call |= checkGraphicsOrComputeBit(dev_data, flags, cmdTypeToString(cmd).c_str());
3437cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
3438cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_SETVIEWPORTSTATE:
3439cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_SETSCISSORSTATE:
3440cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_SETLINEWIDTHSTATE:
3441cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_SETDEPTHBIASSTATE:
3442cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_SETBLENDSTATE:
3443cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_SETDEPTHBOUNDSSTATE:
3444cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_SETSTENCILREADMASKSTATE:
3445cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_SETSTENCILWRITEMASKSTATE:
3446cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_SETSTENCILREFERENCESTATE:
3447cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_BINDINDEXBUFFER:
3448cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_BINDVERTEXBUFFER:
3449cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_DRAW:
3450cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_DRAWINDEXED:
3451cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_DRAWINDIRECT:
3452cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_DRAWINDEXEDINDIRECT:
3453cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_BLITIMAGE:
3454cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_CLEARATTACHMENTS:
3455cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_CLEARDEPTHSTENCILIMAGE:
3456cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_RESOLVEIMAGE:
3457cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_BEGINRENDERPASS:
3458cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_NEXTSUBPASS:
3459cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_ENDRENDERPASS:
346051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                skip_call |= checkGraphicsBit(dev_data, flags, cmdTypeToString(cmd).c_str());
3461cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
3462cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_DISPATCH:
3463cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_DISPATCHINDIRECT:
346451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                skip_call |= checkComputeBit(dev_data, flags, cmdTypeToString(cmd).c_str());
3465cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
3466cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_COPYBUFFER:
3467cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_COPYIMAGE:
3468cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_COPYBUFFERTOIMAGE:
3469cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_COPYIMAGETOBUFFER:
3470cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_CLONEIMAGEDATA:
3471cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_UPDATEBUFFER:
3472cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_PIPELINEBARRIER:
3473cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_EXECUTECOMMANDS:
3474cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_END:
3475cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
3476cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
3477cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
34785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
34795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
34805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB->state != CB_RECORDING) {
348151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        skip_call |= report_error_no_cb_begin(dev_data, pCB->commandBuffer, caller_name);
34827651c2eb9fe152ba62921ed60454afd882357e2aTobin Ehlis    } else {
348351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        skip_call |= ValidateCmdSubpassState(dev_data, pCB, cmd);
34845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
348583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
34865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
348729f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis
34881ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlisvoid UpdateCmdBufferLastCmd(GLOBAL_CB_NODE *cb_state, const CMD_TYPE cmd) {
348929f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis    if (cb_state->state == CB_RECORDING) {
349029f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        cb_state->last_cmd = cmd;
349129f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis    }
349229f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis}
34937e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis// For given object struct return a ptr of BASE_NODE type for its wrapping struct
34947e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin EhlisBASE_NODE *GetStateStructPtrFromObject(layer_data *dev_data, VK_OBJECT object_struct) {
34957e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    BASE_NODE *base_ptr = nullptr;
34967e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    switch (object_struct.type) {
3497cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT: {
34989a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetSetNode(dev_data, reinterpret_cast<VkDescriptorSet &>(object_struct.handle));
3499cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3500cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3501cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT: {
35029a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetSamplerState(dev_data, reinterpret_cast<VkSampler &>(object_struct.handle));
3503cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3504cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3505cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT: {
35069a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetQueryPoolNode(dev_data, reinterpret_cast<VkQueryPool &>(object_struct.handle));
3507cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3508cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3509cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT: {
3510cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            base_ptr = getPipelineState(dev_data, reinterpret_cast<VkPipeline &>(object_struct.handle));
3511cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3512cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3513cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT: {
35149a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetBufferState(dev_data, reinterpret_cast<VkBuffer &>(object_struct.handle));
3515cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3516cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3517cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT: {
35189a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetBufferViewState(dev_data, reinterpret_cast<VkBufferView &>(object_struct.handle));
3519cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3520cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3521cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT: {
35229a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetImageState(dev_data, reinterpret_cast<VkImage &>(object_struct.handle));
3523cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3524cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3525cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT: {
35269a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetImageViewState(dev_data, reinterpret_cast<VkImageView &>(object_struct.handle));
3527cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3528cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3529cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT: {
35309a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetEventNode(dev_data, reinterpret_cast<VkEvent &>(object_struct.handle));
3531cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3532cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3533cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT: {
35349a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetDescriptorPoolState(dev_data, reinterpret_cast<VkDescriptorPool &>(object_struct.handle));
3535cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3536cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3537cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT: {
35389a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetCommandPoolNode(dev_data, reinterpret_cast<VkCommandPool &>(object_struct.handle));
3539cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3540cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3541cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT: {
35429a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetFramebufferState(dev_data, reinterpret_cast<VkFramebuffer &>(object_struct.handle));
3543cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3544cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3545cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT: {
35469a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetRenderPassState(dev_data, reinterpret_cast<VkRenderPass &>(object_struct.handle));
3547cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3548cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3549cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT: {
35509a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetMemObjInfo(dev_data, reinterpret_cast<VkDeviceMemory &>(object_struct.handle));
3551cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3552cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3553cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
3554cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // TODO : Any other objects to be handled here?
3555cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            assert(0);
3556cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3557bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis    }
35587e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    return base_ptr;
35597e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis}
35607e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis
35617e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis// Tie the VK_OBJECT to the cmd buffer which includes:
35627e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis//  Add object_binding to cmd buffer
35637e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis//  Add cb_binding to object
35647e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlisstatic void addCommandBufferBinding(std::unordered_set<GLOBAL_CB_NODE *> *cb_bindings, VK_OBJECT obj, GLOBAL_CB_NODE *cb_node) {
35657e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    cb_bindings->insert(cb_node);
35667e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    cb_node->object_bindings.insert(obj);
35677e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis}
35687e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis// For a given object, if cb_node is in that objects cb_bindings, remove cb_node
35697e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlisstatic void removeCommandBufferBinding(layer_data *dev_data, VK_OBJECT const *object, GLOBAL_CB_NODE *cb_node) {
35707e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    BASE_NODE *base_obj = GetStateStructPtrFromObject(dev_data, *object);
3571cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (base_obj) base_obj->cb_bindings.erase(cb_node);
3572bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis}
35735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Reset the command buffer state
35745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Maintain the createInfo and set state to CB_NEW, but clear all other state
3575400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlisstatic void resetCB(layer_data *dev_data, const VkCommandBuffer cb) {
3576400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis    GLOBAL_CB_NODE *pCB = dev_data->commandBufferMap[cb];
35775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
3578b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine        pCB->in_use.store(0);
3579347d4d3139a1e743ed85bd375c20fd35bbe68d74Chris Forbes        pCB->last_cmd = CMD_NONE;
35805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Reset CB state (note that createInfo is not cleared)
35815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->commandBuffer = cb;
35825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        memset(&pCB->beginInfo, 0, sizeof(VkCommandBufferBeginInfo));
35835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        memset(&pCB->inheritanceInfo, 0, sizeof(VkCommandBufferInheritanceInfo));
35845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->numCmds = 0;
35855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        memset(pCB->drawCount, 0, NUM_DRAW_TYPES * sizeof(uint64_t));
35865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->state = CB_NEW;
35875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->submitCount = 0;
35885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status = 0;
3589b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes        pCB->viewportMask = 0;
3590b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes        pCB->scissorMask = 0;
359193c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski
359272d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis        for (uint32_t i = 0; i < VK_PIPELINE_BIND_POINT_RANGE_SIZE; ++i) {
359372d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis            pCB->lastBound[i].reset();
359472d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis        }
359593c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski
35965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        memset(&pCB->activeRenderPassBeginInfo, 0, sizeof(pCB->activeRenderPassBeginInfo));
3597ee691f5c5fa87aac3750454d2bca2cb582e4e817Chris Forbes        pCB->activeRenderPass = nullptr;
35985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->activeSubpassContents = VK_SUBPASS_CONTENTS_INLINE;
35995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->activeSubpass = 0;
3600e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis        pCB->broken_bindings.clear();
36015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->waitedEvents.clear();
36025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->events.clear();
3603c7e6bc41aa9c6e5a677b138b9459b252cd3bedf2Mark Lobodzinski        pCB->writeEventsBeforeWait.clear();
36045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->waitedEventsBeforeQueryReset.clear();
36055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->queryToStateMap.clear();
36065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->activeQueries.clear();
36075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->startedQueries.clear();
3608abfafae4ec5d76e520916b03d196e474e972c949Michael Lentine        pCB->imageSubresourceMap.clear();
36095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->imageLayoutMap.clear();
36105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->eventToStageMap.clear();
36115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->drawData.clear();
36125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->currentDrawData.buffers.clear();
361358b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis        pCB->vertex_buffer_used = false;
36145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->primaryCommandBuffer = VK_NULL_HANDLE;
3615bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        // Make sure any secondaryCommandBuffers are removed from globalInFlight
3616bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        for (auto secondary_cb : pCB->secondaryCommandBuffers) {
3617bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis            dev_data->globalInFlightCmdBuffers.erase(secondary_cb);
3618bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        }
36195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->secondaryCommandBuffers.clear();
36207a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        pCB->updateImages.clear();
36217a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        pCB->updateBuffers.clear();
3622400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis        clear_cmd_buf_and_mem_references(dev_data, pCB);
3623b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        pCB->eventUpdates.clear();
3624d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        pCB->queryUpdates.clear();
362593c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski
3626bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis        // Remove object bindings
3627bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis        for (auto obj : pCB->object_bindings) {
3628bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis            removeCommandBufferBinding(dev_data, &obj, pCB);
3629bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis        }
3630a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis        pCB->object_bindings.clear();
363193c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski        // Remove this cmdBuffer's reference from each FrameBuffer's CB ref list
363293c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski        for (auto framebuffer : pCB->framebuffers) {
36339a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto fb_state = GetFramebufferState(dev_data, framebuffer);
3634cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (fb_state) fb_state->cb_bindings.erase(pCB);
363593c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski        }
363693c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski        pCB->framebuffers.clear();
36377003b38da5cc27a063af3c45080f3a35438283eeTobin Ehlis        pCB->activeFramebuffer = VK_NULL_HANDLE;
36385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
36395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
36405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
36415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Set PSO-related status bits for CB, including dynamic state set via PSO
36424c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic void set_cb_pso_status(GLOBAL_CB_NODE *pCB, const PIPELINE_STATE *pPipe) {
36435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Account for any dynamic state not set via this PSO
3644ca546210846c65808717f8875deae39bd227c240Tobin Ehlis    if (!pPipe->graphicsPipelineCI.pDynamicState ||
3645cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        !pPipe->graphicsPipelineCI.pDynamicState->dynamicStateCount) {  // All state is static
36464052946ae557337ff95f3725e879131b1c63f865Tobin Ehlis        pCB->status |= CBSTATUS_ALL_STATE_SET;
36475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
36485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // First consider all state on
36495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Then unset any state that's noted as dynamic in PSO
36505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Finally OR that into CB statemask
36514052946ae557337ff95f3725e879131b1c63f865Tobin Ehlis        CBStatusFlags psoDynStateMask = CBSTATUS_ALL_STATE_SET;
3652ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        for (uint32_t i = 0; i < pPipe->graphicsPipelineCI.pDynamicState->dynamicStateCount; i++) {
3653ca546210846c65808717f8875deae39bd227c240Tobin Ehlis            switch (pPipe->graphicsPipelineCI.pDynamicState->pDynamicStates[i]) {
3654cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_LINE_WIDTH:
3655cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_LINE_WIDTH_SET;
3656cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3657cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_DEPTH_BIAS:
3658cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_DEPTH_BIAS_SET;
3659cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3660cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_BLEND_CONSTANTS:
3661cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_BLEND_CONSTANTS_SET;
3662cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3663cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_DEPTH_BOUNDS:
3664cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_DEPTH_BOUNDS_SET;
3665cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3666cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK:
3667cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_STENCIL_READ_MASK_SET;
3668cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3669cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_STENCIL_WRITE_MASK:
3670cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_STENCIL_WRITE_MASK_SET;
3671cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3672cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_STENCIL_REFERENCE:
3673cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_STENCIL_REFERENCE_SET;
3674cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3675cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                default:
3676cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    // TODO : Flag error here
3677cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
36785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
36795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
36805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= psoDynStateMask;
36815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
36825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
36835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3684623784ad78c8b77a78c4db613db974c12e5f5a43Mark Lobodzinski// Flags validation error if the associated call is made inside a render pass. The apiName routine should ONLY be called outside a
3685623784ad78c8b77a78c4db613db974c12e5f5a43Mark Lobodzinski// render pass.
368651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisbool insideRenderPass(const layer_data *dev_data, GLOBAL_CB_NODE *pCB, const char *apiName, UNIQUE_VALIDATION_ERROR_CODE msgCode) {
3687e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool inside = false;
36885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB->activeRenderPass) {
368951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        inside = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3690ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                         (uint64_t)pCB->commandBuffer, __LINE__, msgCode, "DS",
3691ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                         "%s: It is invalid to issue this call inside an active render pass (0x%" PRIxLEAST64 "). %s", apiName,
3692ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                         (uint64_t)pCB->activeRenderPass->renderPass, validation_error_map[msgCode]);
36935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
36945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return inside;
36955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
36965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
36975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Flags validation error if the associated call is made outside a render pass. The apiName
36985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// routine should ONLY be called inside a render pass.
369951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisbool outsideRenderPass(const layer_data *dev_data, GLOBAL_CB_NODE *pCB, const char *apiName, UNIQUE_VALIDATION_ERROR_CODE msgCode) {
3700e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool outside = false;
37015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (((pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_PRIMARY) && (!pCB->activeRenderPass)) ||
37025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        ((pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY) && (!pCB->activeRenderPass) &&
37035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis         !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT))) {
370451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        outside = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3705ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                          (uint64_t)pCB->commandBuffer, __LINE__, msgCode, "DS",
3706ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                          "%s: This call must be issued inside an active render pass. %s", apiName, validation_error_map[msgCode]);
37075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
37085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return outside;
37095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
37105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3711f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbesstatic void init_core_validation(instance_layer_data *instance_data, const VkAllocationCallbacks *pAllocator) {
3712b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis    layer_debug_actions(instance_data->report_data, instance_data->logging_callback, pAllocator, "lunarg_core_validation");
37135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
37145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3715747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbesstatic void checkInstanceRegisterExtensions(const VkInstanceCreateInfo *pCreateInfo, instance_layer_data *instance_data) {
3716747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
3717747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_SURFACE_EXTENSION_NAME))
3718747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->surfaceExtensionEnabled = true;
3719747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_DISPLAY_EXTENSION_NAME))
3720747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->displayExtensionEnabled = true;
3721747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_ANDROID_KHR
3722747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_ANDROID_SURFACE_EXTENSION_NAME))
3723747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->androidSurfaceExtensionEnabled = true;
3724747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#endif
3725747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_MIR_KHR
3726747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_MIR_SURFACE_EXTENSION_NAME))
3727747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->mirSurfaceExtensionEnabled = true;
3728747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#endif
3729747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WAYLAND_KHR
3730747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME))
3731747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->waylandSurfaceExtensionEnabled = true;
3732747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#endif
3733747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WIN32_KHR
3734747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_WIN32_SURFACE_EXTENSION_NAME))
3735747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->win32SurfaceExtensionEnabled = true;
3736747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#endif
3737747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XCB_KHR
3738747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_XCB_SURFACE_EXTENSION_NAME))
3739747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->xcbSurfaceExtensionEnabled = true;
3740747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#endif
3741747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XLIB_KHR
3742747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_XLIB_SURFACE_EXTENSION_NAME))
3743747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->xlibSurfaceExtensionEnabled = true;
3744747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#endif
3745747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
3746747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
3747747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
3748bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
3749bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              VkInstance *pInstance) {
37505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkLayerInstanceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
37515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
37525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(chain_info->u.pLayerInfo);
37535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
37545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance");
3755cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (fpCreateInstance == NULL) return VK_ERROR_INITIALIZATION_FAILED;
37565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
37575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Advance the link info for the next element on the chain
37585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
37595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
37605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
3761cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (result != VK_SUCCESS) return result;
37625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
376356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(*pInstance), instance_layer_data_map);
376456a5ba3e60a723781945959ffc10e2e215350de5Chia-I Wu    instance_data->instance = *pInstance;
37659172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    layer_init_instance_dispatch_table(*pInstance, &instance_data->dispatch_table, fpGetInstanceProcAddr);
37669172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    instance_data->report_data = debug_report_create_instance(
37679172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes        &instance_data->dispatch_table, *pInstance, pCreateInfo->enabledExtensionCount, pCreateInfo->ppEnabledExtensionNames);
3768747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    checkInstanceRegisterExtensions(pCreateInfo, instance_data);
3769b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis    init_core_validation(instance_data, pAllocator);
3770825ac70f99460ccb9494d34f93d8ee7ec303e5deMark Lobodzinski
37715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    ValidateLayerOrdering(*pCreateInfo);
37725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
37735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
37745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
37755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
377625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// Hook DestroyInstance to remove tableInstanceMap entry
377789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL DestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
37785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODOSC : Shouldn't need any customization here
37795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dispatch_key key = get_dispatch_key(instance);
37805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TBD: Need any locking this early, in case this function is called at the
37815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // same time by more than one thread?
378256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(key, instance_layer_data_map);
37839172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    instance_data->dispatch_table.DestroyInstance(instance, pAllocator);
37845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3785b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::lock_guard<std::mutex> lock(global_lock);
37865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Clean up logging callback, if any
37879172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    while (instance_data->logging_callback.size() > 0) {
37889172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes        VkDebugReportCallbackEXT callback = instance_data->logging_callback.back();
37899172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes        layer_destroy_msg_callback(instance_data->report_data, callback, pAllocator);
37909172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes        instance_data->logging_callback.pop_back();
37915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
37925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
37939172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    layer_debug_report_destroy_instance(instance_data->report_data);
37945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data_map.erase(key);
37955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
37965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3797373469f006399d6b5204ee05db3b56beb168b36fMark Youngstatic void checkDeviceRegisterExtensions(const VkDeviceCreateInfo *pCreateInfo, VkDevice device) {
37985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t i;
3799bee1d36c54af112766d4e8552ad302f39290683aMark Lobodzinski    // TBD: Need any locking, in case this function is called at the same time by more than one thread?
380056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
38015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->device_extensions.wsi_enabled = false;
3802c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young    dev_data->device_extensions.wsi_display_swapchain_enabled = false;
3803bee1d36c54af112766d4e8552ad302f39290683aMark Lobodzinski    dev_data->device_extensions.nv_glsl_shader_enabled = false;
38045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
38055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
3806bee1d36c54af112766d4e8552ad302f39290683aMark Lobodzinski        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0) {
38075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->device_extensions.wsi_enabled = true;
3808bee1d36c54af112766d4e8552ad302f39290683aMark Lobodzinski        }
3809bee1d36c54af112766d4e8552ad302f39290683aMark Lobodzinski        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME) == 0) {
3810c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young            dev_data->device_extensions.wsi_display_swapchain_enabled = true;
3811bee1d36c54af112766d4e8552ad302f39290683aMark Lobodzinski        }
3812bee1d36c54af112766d4e8552ad302f39290683aMark Lobodzinski        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_NV_GLSL_SHADER_EXTENSION_NAME) == 0) {
3813bee1d36c54af112766d4e8552ad302f39290683aMark Lobodzinski            dev_data->device_extensions.nv_glsl_shader_enabled = true;
3814bee1d36c54af112766d4e8552ad302f39290683aMark Lobodzinski        }
38155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
38165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
38175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3818838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski// Verify that queue family has been properly requested
3819ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblenstatic bool ValidateRequestedQueueFamilyProperties(instance_layer_data *instance_data, VkPhysicalDevice gpu,
3820ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                                                   const VkDeviceCreateInfo *create_info) {
3821838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski    bool skip_call = false;
38229a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, gpu);
3823838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski    // First check is app has actually requested queueFamilyProperties
38244b293996aa6a9bd92ef1f0175eca4b0e8a9fd9fcChris Forbes    if (!physical_device_state) {
3825bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        skip_call |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
3826bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVLIMITS_MUST_QUERY_COUNT, "DL",
3827838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski                             "Invalid call to vkCreateDevice() w/o first calling vkEnumeratePhysicalDevices().");
38284b293996aa6a9bd92ef1f0175eca4b0e8a9fd9fcChris Forbes    } else if (QUERY_DETAILS != physical_device_state->vkGetPhysicalDeviceQueueFamilyPropertiesState) {
3829838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski        // TODO: This is not called out as an invalid use in the spec so make more informative recommendation.
38304b293996aa6a9bd92ef1f0175eca4b0e8a9fd9fcChris Forbes        skip_call |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
3831838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski                             VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVLIMITS_INVALID_QUEUE_CREATE_REQUEST,
3832838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski                             "DL", "Call to vkCreateDevice() w/o first calling vkGetPhysicalDeviceQueueFamilyProperties().");
3833838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski    } else {
3834838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski        // Check that the requested queue properties are valid
3835838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski        for (uint32_t i = 0; i < create_info->queueCreateInfoCount; i++) {
3836838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski            uint32_t requestedIndex = create_info->pQueueCreateInfos[i].queueFamilyIndex;
38377d8b6ab1b68c397da50bad43deb1fba389ebace7Chris Forbes            if (requestedIndex >= physical_device_state->queue_family_properties.size()) {
3838838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski                skip_call |= log_msg(
38394b293996aa6a9bd92ef1f0175eca4b0e8a9fd9fcChris Forbes                    instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0,
3840838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski                    __LINE__, DEVLIMITS_INVALID_QUEUE_CREATE_REQUEST, "DL",
3841838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski                    "Invalid queue create request in vkCreateDevice(). Invalid queueFamilyIndex %u requested.", requestedIndex);
3842838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski            } else if (create_info->pQueueCreateInfos[i].queueCount >
38437d8b6ab1b68c397da50bad43deb1fba389ebace7Chris Forbes                       physical_device_state->queue_family_properties[requestedIndex].queueCount) {
3844cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                skip_call |= log_msg(
3845cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0,
3846cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    __LINE__, DEVLIMITS_INVALID_QUEUE_CREATE_REQUEST, "DL",
3847cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "Invalid queue create request in vkCreateDevice(). QueueFamilyIndex %u only has %u queues, but "
3848cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "requested queueCount is %u.",
3849cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    requestedIndex, physical_device_state->queue_family_properties[requestedIndex].queueCount,
3850cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    create_info->pQueueCreateInfos[i].queueCount);
3851838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski            }
3852838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski        }
3853838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski    }
3854838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski    return skip_call;
3855838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski}
3856838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski
3857f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski// Verify that features have been queried and that they are available
3858bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool ValidateRequestedFeatures(instance_layer_data *dev_data, VkPhysicalDevice phys,
3859bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                      const VkPhysicalDeviceFeatures *requested_features) {
3860f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    bool skip_call = false;
3861f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
38629a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto phys_device_state = GetPhysicalDeviceState(dev_data, phys);
38633bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes    const VkBool32 *actual = reinterpret_cast<VkBool32 *>(&phys_device_state->features);
3864825ac70f99460ccb9494d34f93d8ee7ec303e5deMark Lobodzinski    const VkBool32 *requested = reinterpret_cast<const VkBool32 *>(requested_features);
3865f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    // TODO : This is a nice, compact way to loop through struct, but a bad way to report issues
3866f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    //  Need to provide the struct member name with the issue. To do that seems like we'll
3867f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    //  have to loop through each struct member which should be done w/ codegen to keep in synch.
3868f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    uint32_t errors = 0;
3869f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    uint32_t total_bools = sizeof(VkPhysicalDeviceFeatures) / sizeof(VkBool32);
3870f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    for (uint32_t i = 0; i < total_bools; i++) {
3871f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski        if (requested[i] > actual[i]) {
3872f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski            // TODO: Add index to struct member name helper to be able to include a feature name
3873cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            skip_call |=
3874cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0,
3875cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        __LINE__, DEVLIMITS_INVALID_FEATURE_REQUESTED, "DL",
3876cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "While calling vkCreateDevice(), requesting feature #%u in VkPhysicalDeviceFeatures struct, "
3877cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "which is not available on this device.",
3878cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        i);
3879f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski            errors++;
3880f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski        }
3881f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    }
38823bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes    if (errors && (UNCALLED == phys_device_state->vkGetPhysicalDeviceFeaturesState)) {
3883f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski        // If user didn't request features, notify them that they should
3884f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski        // TODO: Verify this against the spec. I believe this is an invalid use of the API and should return an error
3885bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
3886bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             0, __LINE__, DEVLIMITS_INVALID_FEATURE_REQUESTED, "DL",
3887bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             "You requested features that are unavailable on this device. You should first query feature "
3888bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             "availability by calling vkGetPhysicalDeviceFeatures().");
3889f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    }
3890f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    return skip_call;
3891f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski}
3892f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
389389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo,
389489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                            const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
389556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(gpu), instance_layer_data_map);
3896f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    bool skip_call = false;
3897f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
3898f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    // Check that any requested features are available
3899f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    if (pCreateInfo->pEnabledFeatures) {
390056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        skip_call |= ValidateRequestedFeatures(instance_data, gpu, pCreateInfo->pEnabledFeatures);
3901f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    }
390256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    skip_call |= ValidateRequestedQueueFamilyProperties(instance_data, gpu, pCreateInfo);
3903f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
39041d659b4113b77a95325df10d602a03f1e7abf8b7Mark Mueller    if (skip_call) {
39051d659b4113b77a95325df10d602a03f1e7abf8b7Mark Mueller        return VK_ERROR_VALIDATION_FAILED_EXT;
39061d659b4113b77a95325df10d602a03f1e7abf8b7Mark Mueller    }
39071d659b4113b77a95325df10d602a03f1e7abf8b7Mark Mueller
39085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkLayerDeviceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
39095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
39105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(chain_info->u.pLayerInfo);
39115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
39125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;
391356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(instance_data->instance, "vkCreateDevice");
39145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (fpCreateDevice == NULL) {
39155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return VK_ERROR_INITIALIZATION_FAILED;
39165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
39175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
39185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Advance the link info for the next element on the chain
39195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
39205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
39215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = fpCreateDevice(gpu, pCreateInfo, pAllocator, pDevice);
39225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result != VK_SUCCESS) {
39235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return result;
39245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
39255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3926b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
392756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(*pDevice), layer_data_map);
39285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
392956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    device_data->instance_data = instance_data;
39305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Setup device dispatch table
393156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_init_device_dispatch_table(*pDevice, &device_data->dispatch_table, fpGetDeviceProcAddr);
393256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    device_data->device = *pDevice;
3933ec85232c4d8d9ddf7d2ae57cb8203c5ab52c1106Mark Lobodzinski    // Save PhysicalDevice handle
393456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    device_data->physical_device = gpu;
39355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
393656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    device_data->report_data = layer_debug_report_create_device(instance_data->report_data, *pDevice);
3937373469f006399d6b5204ee05db3b56beb168b36fMark Young    checkDeviceRegisterExtensions(pCreateInfo, *pDevice);
39385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Get physical device limits for this device
393956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceProperties(gpu, &(device_data->phys_dev_properties.properties));
39405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t count;
394156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties(gpu, &count, nullptr);
394256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    device_data->phys_dev_properties.queue_family_properties.resize(count);
394356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties(
394456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        gpu, &count, &device_data->phys_dev_properties.queue_family_properties[0]);
39455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO: device limits should make sure these are compatible
39465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCreateInfo->pEnabledFeatures) {
394756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        device_data->enabled_features = *pCreateInfo->pEnabledFeatures;
39485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
394956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        memset(&device_data->enabled_features, 0, sizeof(VkPhysicalDeviceFeatures));
39505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
3951e47dbc3f3340fa177d877a67b2adb76a570027e5Mark Lobodzinski    // Store physical device properties and physical device mem limits into device layer_data structs
395256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceMemoryProperties(gpu, &device_data->phys_dev_mem_props);
395356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceProperties(gpu, &device_data->phys_dev_props);
3954b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
39555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
39565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    ValidateLayerOrdering(*pCreateInfo);
39575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
39585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
39595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
39605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
39615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// prototype
396289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL DestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) {
39635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODOSC : Shouldn't need any customization here
39643ec39aeb6d6f08fb1ee45f64f72543a710754c62Tobin Ehlis    bool skip = false;
39655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dispatch_key key = get_dispatch_key(device);
396656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(key, layer_data_map);
39675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Free all the memory
3968b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
39695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    deletePipelines(dev_data);
3970fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    dev_data->renderPassMap.clear();
39715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    deleteCommandBuffers(dev_data);
3972f13bee0887f3c3d1d597c82869864be3be836737Tobin Ehlis    // This will also delete all sets in the pool & remove them from setMap
39735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    deletePools(dev_data);
3974f13bee0887f3c3d1d597c82869864be3be836737Tobin Ehlis    // All sets should be removed
3975f13bee0887f3c3d1d597c82869864be3be836737Tobin Ehlis    assert(dev_data->setMap.empty());
3976a1e5173c89eb7f03e0434ad45ccd1471e722fa71Tobin Ehlis    for (auto del_layout : dev_data->descriptorSetLayoutMap) {
3977a1e5173c89eb7f03e0434ad45ccd1471e722fa71Tobin Ehlis        delete del_layout.second;
3978a1e5173c89eb7f03e0434ad45ccd1471e722fa71Tobin Ehlis    }
3979fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis    dev_data->descriptorSetLayoutMap.clear();
39805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->imageViewMap.clear();
39815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->imageMap.clear();
39825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->imageSubresourceMap.clear();
39835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->imageLayoutMap.clear();
39845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->bufferViewMap.clear();
39855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->bufferMap.clear();
39861344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis    // Queues persist until device is destroyed
39871344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis    dev_data->queueMap.clear();
39885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Report any memory leaks
39895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_debug_report_destroy_device(device);
3990b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
39915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
39925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#if DISPATCH_MAP_DEBUG
3993414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller    fprintf(stderr, "Device: 0x%p, key: 0x%p\n", device, key);
39945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#endif
39953ec39aeb6d6f08fb1ee45f64f72543a710754c62Tobin Ehlis    if (!skip) {
39964a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyDevice(device, pAllocator);
39973ec39aeb6d6f08fb1ee45f64f72543a710754c62Tobin Ehlis        layer_data_map.erase(key);
39985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
39995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
40005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
40015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic const VkExtensionProperties instance_extensions[] = {{VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION}};
40025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4003208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis// For given stage mask, if Geometry shader stage is on w/o GS being enabled, report geo_error_id
4004208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis//   and if Tessellation Control or Evaluation shader stages are on w/o TS being enabled, report tess_error_id
4005208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlisstatic bool ValidateStageMaskGsTsEnables(layer_data *dev_data, VkPipelineStageFlags stageMask, const char *caller,
4006208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                                         UNIQUE_VALIDATION_ERROR_CODE geo_error_id, UNIQUE_VALIDATION_ERROR_CODE tess_error_id) {
4007208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    bool skip = false;
4008208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    if (!dev_data->enabled_features.geometryShader && (stageMask & VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT)) {
4009208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
4010cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        geo_error_id, "DL",
4011cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "%s call includes a stageMask with VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT bit set when "
4012cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "device does not have geometryShader feature enabled. %s",
4013208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                        caller, validation_error_map[geo_error_id]);
4014208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    }
4015208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    if (!dev_data->enabled_features.tessellationShader &&
4016208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        (stageMask & (VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT | VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT))) {
4017208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
4018cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        tess_error_id, "DL",
4019cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "%s call includes a stageMask with VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT "
4020cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "and/or VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT bit(s) set when device "
4021cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "does not have tessellationShader feature enabled. %s",
4022208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                        caller, validation_error_map[tess_error_id]);
4023208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    }
4024208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    return skip;
4025208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis}
4026208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis
402751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour// Loop through bound objects and increment their in_use counts if increment parameter is true
402851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour// or flag an error if unknown objects are found
402951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic bool ValidateOrIncrementBoundObjects(layer_data *dev_data, GLOBAL_CB_NODE const *cb_node, bool increment) {
4030162dac96d3883e8fffaa1f988043f62c06662d2eTobin Ehlis    bool skip = false;
4031162dac96d3883e8fffaa1f988043f62c06662d2eTobin Ehlis    DRAW_STATE_ERROR error_code = DRAWSTATE_NONE;
4032162dac96d3883e8fffaa1f988043f62c06662d2eTobin Ehlis    BASE_NODE *base_obj = nullptr;
4033a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    for (auto obj : cb_node->object_bindings) {
4034a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis        switch (obj.type) {
4035cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT: {
40369a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                base_obj = GetSetNode(dev_data, reinterpret_cast<VkDescriptorSet &>(obj.handle));
4037cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_DESCRIPTOR_SET;
4038cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4039cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4040cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT: {
40419a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                base_obj = GetSamplerState(dev_data, reinterpret_cast<VkSampler &>(obj.handle));
4042cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_SAMPLER;
4043cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4044cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4045cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT: {
40469a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                base_obj = GetQueryPoolNode(dev_data, reinterpret_cast<VkQueryPool &>(obj.handle));
4047cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_QUERY_POOL;
4048cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4049cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4050cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT: {
4051cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                base_obj = getPipelineState(dev_data, reinterpret_cast<VkPipeline &>(obj.handle));
4052cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_PIPELINE;
4053cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4054cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4055cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT: {
40569a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                base_obj = GetBufferState(dev_data, reinterpret_cast<VkBuffer &>(obj.handle));
4057cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_BUFFER;
4058cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4059cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4060cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT: {
40619a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                base_obj = GetBufferViewState(dev_data, reinterpret_cast<VkBufferView &>(obj.handle));
4062cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_BUFFER_VIEW;
4063cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4064cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4065cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT: {
40669a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                base_obj = GetImageState(dev_data, reinterpret_cast<VkImage &>(obj.handle));
4067cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_IMAGE;
4068cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4069cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4070cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT: {
40719a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                base_obj = GetImageViewState(dev_data, reinterpret_cast<VkImageView &>(obj.handle));
4072cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_IMAGE_VIEW;
4073cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4074cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4075cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT: {
40769a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                base_obj = GetEventNode(dev_data, reinterpret_cast<VkEvent &>(obj.handle));
4077cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_EVENT;
4078cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4079cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4080cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT: {
40819a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                base_obj = GetDescriptorPoolState(dev_data, reinterpret_cast<VkDescriptorPool &>(obj.handle));
4082cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_DESCRIPTOR_POOL;
4083cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4084cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4085cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT: {
40869a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                base_obj = GetCommandPoolNode(dev_data, reinterpret_cast<VkCommandPool &>(obj.handle));
4087cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_COMMAND_POOL;
4088cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4089cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4090cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT: {
40919a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                base_obj = GetFramebufferState(dev_data, reinterpret_cast<VkFramebuffer &>(obj.handle));
4092cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_FRAMEBUFFER;
4093cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4094cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4095cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT: {
40969a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                base_obj = GetRenderPassState(dev_data, reinterpret_cast<VkRenderPass &>(obj.handle));
4097cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_RENDERPASS;
4098cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4099cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4100cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT: {
41019a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                base_obj = GetMemObjInfo(dev_data, reinterpret_cast<VkDeviceMemory &>(obj.handle));
4102cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_DEVICE_MEMORY;
4103cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4104cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4105cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
4106cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // TODO : Merge handling of other objects types into this code
4107cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4108a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis        }
410951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        if (base_obj && increment) {
411051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            base_obj->in_use.fetch_add(1);
411151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        } else if (!base_obj && !increment) {
4112162dac96d3883e8fffaa1f988043f62c06662d2eTobin Ehlis            skip |=
4113162dac96d3883e8fffaa1f988043f62c06662d2eTobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, obj.type, obj.handle, __LINE__, error_code, "DS",
4114162dac96d3883e8fffaa1f988043f62c06662d2eTobin Ehlis                        "Cannot submit cmd buffer using deleted %s 0x%" PRIx64 ".", object_type_to_string(obj.type), obj.handle);
4115162dac96d3883e8fffaa1f988043f62c06662d2eTobin Ehlis        }
4116a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    }
4117162dac96d3883e8fffaa1f988043f62c06662d2eTobin Ehlis    return skip;
4118a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis}
41195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Track which resources are in-flight by atomically incrementing their "in_use" count
412051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic void incrementResources(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
412151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    cb_node->submitCount++;
41229a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis    cb_node->in_use.fetch_add(1);
41239a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis    dev_data->globalInFlightCmdBuffers.insert(cb_node->commandBuffer);
4124a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
4125a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    // First Increment for all "generic" objects bound to cmd buffer, followed by special-case objects below
412651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    ValidateOrIncrementBoundObjects(dev_data, cb_node, true);
4127a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    // TODO : We should be able to remove the NULL look-up checks from the code below as long as
4128a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    //  all the corresponding cases are verified to cause CB_INVALID state and the CB_INVALID state
4129a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    //  should then be flagged prior to calling this function
41309a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis    for (auto drawDataElement : cb_node->drawData) {
41315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto buffer : drawDataElement.buffers) {
41329a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto buffer_state = GetBufferState(dev_data, buffer);
413351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            if (buffer_state) {
41345cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis                buffer_state->in_use.fetch_add(1);
41355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
41365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
41375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
41389a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis    for (auto event : cb_node->writeEventsBeforeWait) {
41399a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto event_state = GetEventNode(dev_data, event);
4140cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (event_state) event_state->write_in_use++;
4141c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    }
41425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
41435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4144b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis// Note: This function assumes that the global lock is held by the calling thread.
4145b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis// For the given queue, verify the queue state up to the given seq number.
4146b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis// Currently the only check is to make sure that if there are events to be waited on prior to
4147b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis//  a QueryReset, make sure that all such events have been signalled.
414836c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic bool VerifyQueueStateToSeq(layer_data *dev_data, QUEUE_STATE *queue, uint64_t seq) {
4149b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    bool skip = false;
4150b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    auto queue_seq = queue->seq;
415192b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis    std::unordered_map<VkQueue, uint64_t> other_queue_seqs;
415292b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis    auto sub_it = queue->submissions.begin();
4153b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    while (queue_seq < seq) {
415492b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis        for (auto &wait : sub_it->waitSemaphores) {
415592b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis            auto &last_seq = other_queue_seqs[wait.queue];
415692b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis            last_seq = std::max(last_seq, wait.seq);
415792b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis        }
415892b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis        for (auto cb : sub_it->cbs) {
41599a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto cb_node = GetCBNode(dev_data, cb);
4160b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis            if (cb_node) {
4161b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                for (auto queryEventsPair : cb_node->waitedEventsBeforeQueryReset) {
4162b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                    for (auto event : queryEventsPair.second) {
416392b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis                        if (dev_data->eventMap[event].needsSignaled) {
416492b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis                            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
4165b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                                            VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, 0, DRAWSTATE_INVALID_QUERY, "DS",
4166b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                                            "Cannot get query results on queryPool 0x%" PRIx64
4167b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                                            " with index %d which was guarded by unsignaled event 0x%" PRIx64 ".",
4168b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                                            (uint64_t)(queryEventsPair.first.pool), queryEventsPair.first.index, (uint64_t)(event));
4169b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                        }
4170b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                    }
4171b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine                }
4172b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine            }
4173b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine        }
417492b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis        sub_it++;
4175b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis        queue_seq++;
4176b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine    }
417792b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis    for (auto qs : other_queue_seqs) {
41789a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        skip |= VerifyQueueStateToSeq(dev_data, GetQueueState(dev_data, qs.first), qs.second);
417992b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis    }
4180b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    return skip;
4181b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis}
4182b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis
4183b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis// When the given fence is retired, verify outstanding queue operations through the point of the fence
4184b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlisstatic bool VerifyQueueStateToFence(layer_data *dev_data, VkFence fence) {
41859a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto fence_state = GetFenceNode(dev_data, fence);
4186b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    if (VK_NULL_HANDLE != fence_state->signaler.first) {
41879a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        return VerifyQueueStateToSeq(dev_data, GetQueueState(dev_data, fence_state->signaler.first), fence_state->signaler.second);
4188b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    }
4189b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    return false;
4190b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine}
41917d33205c3aa4aba751a2c07f956634aac616f916Chris Forbes
41927d33205c3aa4aba751a2c07f956634aac616f916Chris Forbes// TODO: nuke this completely.
4193b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine// Decrement cmd_buffer in_use and if it goes to 0 remove cmd_buffer from globalInFlightCmdBuffers
4194b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentinestatic inline void removeInFlightCmdBuffer(layer_data *dev_data, VkCommandBuffer cmd_buffer) {
4195b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine    // Pull it off of global list initially, but if we find it in any other queue list, add it back in
41969a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, cmd_buffer);
4197b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine    pCB->in_use.fetch_sub(1);
4198b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine    if (!pCB->in_use.load()) {
4199b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine        dev_data->globalInFlightCmdBuffers.erase(cmd_buffer);
4200b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine    }
4201b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine}
4202b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine
4203a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis// Decrement in-use count for objects bound to command buffer
42042f8cbf3b166e175174877a59929902e005953d6dTobin Ehlisstatic void DecrementBoundResources(layer_data *dev_data, GLOBAL_CB_NODE const *cb_node) {
420500e8ce2e6c1c191758f7b7c15eeaf350e5b4a3b6Tobin Ehlis    BASE_NODE *base_obj = nullptr;
4206a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    for (auto obj : cb_node->object_bindings) {
42077e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis        base_obj = GetStateStructPtrFromObject(dev_data, obj);
420800e8ce2e6c1c191758f7b7c15eeaf350e5b4a3b6Tobin Ehlis        if (base_obj) {
420900e8ce2e6c1c191758f7b7c15eeaf350e5b4a3b6Tobin Ehlis            base_obj->in_use.fetch_sub(1);
421000e8ce2e6c1c191758f7b7c15eeaf350e5b4a3b6Tobin Ehlis        }
4211a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    }
4212a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis}
4213da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes
421436c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic void RetireWorkOnQueue(layer_data *dev_data, QUEUE_STATE *pQueue, uint64_t seq) {
42159867daedbf52debc77d6568162ee21e071699b80Chris Forbes    std::unordered_map<VkQueue, uint64_t> otherQueueSeqs;
42169867daedbf52debc77d6568162ee21e071699b80Chris Forbes
42179867daedbf52debc77d6568162ee21e071699b80Chris Forbes    // Roll this queue forward, one submission at a time.
42189867daedbf52debc77d6568162ee21e071699b80Chris Forbes    while (pQueue->seq < seq) {
4219bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto &submission = pQueue->submissions.front();
42209867daedbf52debc77d6568162ee21e071699b80Chris Forbes
4221bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        for (auto &wait : submission.waitSemaphores) {
42229a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, wait.semaphore);
4223c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            if (pSemaphore) {
4224c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski                pSemaphore->in_use.fetch_sub(1);
4225c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            }
4226bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            auto &lastSeq = otherQueueSeqs[wait.queue];
42279867daedbf52debc77d6568162ee21e071699b80Chris Forbes            lastSeq = std::max(lastSeq, wait.seq);
4228da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes        }
4229cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes
4230bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        for (auto &semaphore : submission.signalSemaphores) {
42319a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
4232c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            if (pSemaphore) {
4233c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski                pSemaphore->in_use.fetch_sub(1);
4234c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            }
42359867daedbf52debc77d6568162ee21e071699b80Chris Forbes        }
4236cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes
42379867daedbf52debc77d6568162ee21e071699b80Chris Forbes        for (auto cb : submission.cbs) {
42389a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto cb_node = GetCBNode(dev_data, cb);
4239c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            if (!cb_node) {
4240c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski                continue;
4241c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            }
4242a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis            // First perform decrement on general case bound objects
42439a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            DecrementBoundResources(dev_data, cb_node);
42449a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            for (auto drawDataElement : cb_node->drawData) {
42459867daedbf52debc77d6568162ee21e071699b80Chris Forbes                for (auto buffer : drawDataElement.buffers) {
42469a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto buffer_state = GetBufferState(dev_data, buffer);
42475cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis                    if (buffer_state) {
42485cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis                        buffer_state->in_use.fetch_sub(1);
42499867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    }
42509867daedbf52debc77d6568162ee21e071699b80Chris Forbes                }
4251da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes            }
42529a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            for (auto event : cb_node->writeEventsBeforeWait) {
42539867daedbf52debc77d6568162ee21e071699b80Chris Forbes                auto eventNode = dev_data->eventMap.find(event);
42549867daedbf52debc77d6568162ee21e071699b80Chris Forbes                if (eventNode != dev_data->eventMap.end()) {
42559867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    eventNode->second.write_in_use--;
42569867daedbf52debc77d6568162ee21e071699b80Chris Forbes                }
42579867daedbf52debc77d6568162ee21e071699b80Chris Forbes            }
42589a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            for (auto queryStatePair : cb_node->queryToStateMap) {
42599867daedbf52debc77d6568162ee21e071699b80Chris Forbes                dev_data->queryToStateMap[queryStatePair.first] = queryStatePair.second;
42609867daedbf52debc77d6568162ee21e071699b80Chris Forbes            }
42619a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            for (auto eventStagePair : cb_node->eventToStageMap) {
42629867daedbf52debc77d6568162ee21e071699b80Chris Forbes                dev_data->eventMap[eventStagePair.first].stageMask = eventStagePair.second;
4263da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes            }
42640a32ed7bdf03e7bda914e03c0bfa6ebf400cdf5bMichael Lentine
42659867daedbf52debc77d6568162ee21e071699b80Chris Forbes            removeInFlightCmdBuffer(dev_data, cb);
42660a32ed7bdf03e7bda914e03c0bfa6ebf400cdf5bMichael Lentine        }
42679867daedbf52debc77d6568162ee21e071699b80Chris Forbes
42689a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto pFence = GetFenceNode(dev_data, submission.fence);
42699867daedbf52debc77d6568162ee21e071699b80Chris Forbes        if (pFence) {
42709867daedbf52debc77d6568162ee21e071699b80Chris Forbes            pFence->state = FENCE_RETIRED;
42710a32ed7bdf03e7bda914e03c0bfa6ebf400cdf5bMichael Lentine        }
42729867daedbf52debc77d6568162ee21e071699b80Chris Forbes
42739867daedbf52debc77d6568162ee21e071699b80Chris Forbes        pQueue->submissions.pop_front();
42749867daedbf52debc77d6568162ee21e071699b80Chris Forbes        pQueue->seq++;
4275b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
42769867daedbf52debc77d6568162ee21e071699b80Chris Forbes
42779867daedbf52debc77d6568162ee21e071699b80Chris Forbes    // Roll other queues forward to the highest seq we saw a wait for
42789867daedbf52debc77d6568162ee21e071699b80Chris Forbes    for (auto qs : otherQueueSeqs) {
42799a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        RetireWorkOnQueue(dev_data, GetQueueState(dev_data, qs.first), qs.second);
4280d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    }
42819867daedbf52debc77d6568162ee21e071699b80Chris Forbes}
4282651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
4283651d92815dfff917308137bb67aacccc4f60df86Chris Forbes// Submit a fence to a queue, delimiting previous fences and previous untracked
4284651d92815dfff917308137bb67aacccc4f60df86Chris Forbes// work by it.
428536c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic void SubmitFence(QUEUE_STATE *pQueue, FENCE_NODE *pFence, uint64_t submitCount) {
4286cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes    pFence->state = FENCE_INFLIGHT;
42879867daedbf52debc77d6568162ee21e071699b80Chris Forbes    pFence->signaler.first = pQueue->queue;
42889867daedbf52debc77d6568162ee21e071699b80Chris Forbes    pFence->signaler.second = pQueue->seq + pQueue->submissions.size() + submitCount;
4289b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine}
4290b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine
429151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic bool validateCommandBufferSimultaneousUse(layer_data *dev_data, GLOBAL_CB_NODE *pCB, int current_submit_count) {
42925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool skip_call = false;
429351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    if ((dev_data->globalInFlightCmdBuffers.count(pCB->commandBuffer) || current_submit_count > 1) &&
42945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
4295226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
4296f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                             0, __LINE__, VALIDATION_ERROR_00133, "DS",
4297f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                             "Command Buffer 0x%p is already in use and is not marked for simultaneous use. %s", pCB->commandBuffer,
4298f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                             validation_error_map[VALIDATION_ERROR_00133]);
42995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
43005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
43015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
43025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4303440bdd357701497c3442e3515f12ac1cfffc180aTony Barbourstatic bool validateCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB, const char *call_source,
4304440bdd357701497c3442e3515f12ac1cfffc180aTony Barbour                                       int current_submit_count) {
4305c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis    bool skip = false;
4306cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.command_buffer_state) return skip;
43070a59acde4b40fde3bbfea5811d2abf2c85ca62f4Tobin Ehlis    // Validate ONE_TIME_SUBMIT_BIT CB is not being submitted more than once
430851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    if ((pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) && (pCB->submitCount + current_submit_count > 1)) {
4309c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
4310c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis                        __LINE__, DRAWSTATE_COMMAND_BUFFER_SINGLE_SUBMIT_VIOLATION, "DS",
4311226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "Commandbuffer 0x%p was begun w/ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT "
4312c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis                        "set, but has been submitted 0x%" PRIxLEAST64 " times.",
431351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                        pCB->commandBuffer, pCB->submitCount + current_submit_count);
43140a59acde4b40fde3bbfea5811d2abf2c85ca62f4Tobin Ehlis    }
43155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Validate that cmd buffers have been updated
43165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (CB_RECORDED != pCB->state) {
43175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (CB_INVALID == pCB->state) {
43185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Inform app of reason CB invalid
4319e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis            for (auto obj : pCB->broken_bindings) {
4320e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis                const char *type_str = object_type_to_string(obj.type);
4321e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis                // Descriptor sets are a special case that can be either destroyed or updated to invalidated a CB
4322e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis                const char *cause_str =
4323e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis                    (obj.type == VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT) ? "destroyed or updated" : "destroyed";
43245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4325c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis                skip |=
43265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
43275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                            reinterpret_cast<uint64_t &>(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
4328226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                            "You are submitting command buffer 0x%p that is invalid because bound %s 0x%" PRIxLEAST64 " was %s.",
4329226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                            pCB->commandBuffer, type_str, obj.handle, cause_str);
43305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
4331cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        } else {  // Flag error for using CB w/o vkEndCommandBuffer() called
4332c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
4333c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis                            (uint64_t)(pCB->commandBuffer), __LINE__, DRAWSTATE_NO_END_COMMAND_BUFFER, "DS",
4334226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                            "You must call vkEndCommandBuffer() on command buffer 0x%p before this call to %s!", pCB->commandBuffer,
4335226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                            call_source);
43365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
43375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
4338c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis    return skip;
43395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
43405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
434151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic bool validateResources(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
434251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    bool skip_call = false;
434351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
434451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    skip_call |= ValidateOrIncrementBoundObjects(dev_data, cb_node, false);
434551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    // TODO : We should be able to remove the NULL look-up checks from the code below as long as
434651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    //  all the corresponding cases are verified to cause CB_INVALID state and the CB_INVALID state
434751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    //  should then be flagged prior to calling this function
434851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    for (auto drawDataElement : cb_node->drawData) {
434951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        for (auto buffer : drawDataElement.buffers) {
435051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            auto buffer_state = GetBufferState(dev_data, buffer);
435151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            if (!buffer_state) {
435251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
435351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                                     (uint64_t)(buffer), __LINE__, DRAWSTATE_INVALID_BUFFER, "DS",
435451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                                     "Cannot submit cmd buffer using deleted buffer 0x%" PRIx64 ".", (uint64_t)(buffer));
435551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            }
435651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        }
435751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    }
435851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    return skip_call;
435951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour}
436051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
43617bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski// Validate that queueFamilyIndices of primary command buffers match this queue
43627bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski// Secondary command buffers were previously validated in vkCmdExecuteCommands().
43637bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinskistatic bool validateQueueFamilyIndices(layer_data *dev_data, GLOBAL_CB_NODE *pCB, VkQueue queue) {
43647bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski    bool skip_call = false;
43659a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pPool = GetCommandPoolNode(dev_data, pCB->createInfo.commandPool);
43669a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto queue_state = GetQueueState(dev_data, queue);
43677bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
436836c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlis    if (pPool && queue_state && (pPool->queueFamilyIndex != queue_state->queueFamilyIndex)) {
43697bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
4370f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                             reinterpret_cast<uint64_t>(pCB->commandBuffer), __LINE__, VALIDATION_ERROR_00139, "DS",
4371f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                             "vkQueueSubmit: Primary command buffer 0x%p created in queue family %d is being submitted on queue "
4372f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                             "0x%p from queue family %d. %s",
4373f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                             pCB->commandBuffer, pPool->queueFamilyIndex, queue, queue_state->queueFamilyIndex,
4374f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                             validation_error_map[VALIDATION_ERROR_00139]);
43757bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski    }
43767bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
43777bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski    return skip_call;
43787bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski}
43797bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
438051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic bool validatePrimaryCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB, int current_submit_count) {
43815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Track in-use for resources off of primary and any secondary CBs
438283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
4383a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
4384a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes    // If USAGE_SIMULTANEOUS_USE_BIT not set then CB cannot already be executing
4385a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes    // on device
438651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    skip_call |= validateCommandBufferSimultaneousUse(dev_data, pCB, current_submit_count);
4387a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
438851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    skip_call |= validateResources(dev_data, pCB);
4389a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
43905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (!pCB->secondaryCommandBuffers.empty()) {
43915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto secondaryCmdBuffer : pCB->secondaryCommandBuffers) {
43929a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            GLOBAL_CB_NODE *pSubCB = GetCBNode(dev_data, secondaryCmdBuffer);
439351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            skip_call |= validateResources(dev_data, pSubCB);
43944c665b29a9d2906a378417546c7fc6436731d07fTobin Ehlis            if ((pSubCB->primaryCommandBuffer != pCB->commandBuffer) &&
43954c665b29a9d2906a378417546c7fc6436731d07fTobin Ehlis                !(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
4396f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                log_msg(
4397f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
4398f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    __LINE__, VALIDATION_ERROR_00135, "DS",
4399f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    "Commandbuffer 0x%p was submitted with secondary buffer 0x%p but that buffer has subsequently been bound to "
4400f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    "primary cmd buffer 0x%p and it does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set. %s",
4401f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    pCB->commandBuffer, secondaryCmdBuffer, pSubCB->primaryCommandBuffer,
4402f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    validation_error_map[VALIDATION_ERROR_00135]);
44035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
44045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
44055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
4406a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
440751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    skip_call |= validateCommandBufferState(dev_data, pCB, "vkQueueSubmit()", current_submit_count);
4408a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
440983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
44105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
44115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4412bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool ValidateFenceForSubmit(layer_data *dev_data, FENCE_NODE *pFence) {
441383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
441481c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes
4415651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    if (pFence) {
4416cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes        if (pFence->state == FENCE_INFLIGHT) {
4417f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen            // TODO: opportunities for VALIDATION_ERROR_00127, VALIDATION_ERROR_01647, VALIDATION_ERROR_01953
441883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
441983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 (uint64_t)(pFence->fence), __LINE__, DRAWSTATE_INVALID_FENCE, "DS",
442083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 "Fence 0x%" PRIx64 " is already in use by another submission.", (uint64_t)(pFence->fence));
4421a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        }
442281c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes
4423cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes        else if (pFence->state == FENCE_RETIRED) {
4424f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen            // TODO: opportunities for VALIDATION_ERROR_00126, VALIDATION_ERROR_01646, VALIDATION_ERROR_01953
442583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |=
442683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
442783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                        reinterpret_cast<uint64_t &>(pFence->fence), __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM",
442883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                        "Fence 0x%" PRIxLEAST64 " submitted in SIGNALED state.  Fences must be reset before being submitted",
442983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                        reinterpret_cast<uint64_t &>(pFence->fence));
4430a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        }
44315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
443281c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes
443383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
443481c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes}
443581c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes
443651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic void PostCallRecordQueueSubmit(layer_data *dev_data, VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits,
443751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                                      VkFence fence) {
44389a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pQueue = GetQueueState(dev_data, queue);
44399a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pFence = GetFenceNode(dev_data, fence);
4440d7d60cccc862fee2d0b3ad410c5fdcc40ddc83aeChris Forbes
4441651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    // Mark the fence in-use.
4442651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    if (pFence) {
44439867daedbf52debc77d6568162ee21e071699b80Chris Forbes        SubmitFence(pQueue, pFence, std::max(1u, submitCount));
4444651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    }
4445651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
444651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    // Now process each individual submit
44475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
444851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        std::vector<VkCommandBuffer> cbs;
44495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubmitInfo *submit = &pSubmits[submit_idx];
44509867daedbf52debc77d6568162ee21e071699b80Chris Forbes        vector<SEMAPHORE_WAIT> semaphore_waits;
44519867daedbf52debc77d6568162ee21e071699b80Chris Forbes        vector<VkSemaphore> semaphore_signals;
44525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < submit->waitSemaphoreCount; ++i) {
445351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            VkSemaphore semaphore = submit->pWaitSemaphores[i];
445451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
445551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            if (pSemaphore) {
445651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                if (pSemaphore->signaler.first != VK_NULL_HANDLE) {
445751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    semaphore_waits.push_back({semaphore, pSemaphore->signaler.first, pSemaphore->signaler.second});
445851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    pSemaphore->in_use.fetch_add(1);
445951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                }
446051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->signaler.first = VK_NULL_HANDLE;
446151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->signaled = false;
446251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            }
446351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        }
446451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        for (uint32_t i = 0; i < submit->signalSemaphoreCount; ++i) {
446551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            VkSemaphore semaphore = submit->pSignalSemaphores[i];
446651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
446751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            if (pSemaphore) {
446851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->signaler.first = queue;
446951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->signaler.second = pQueue->seq + pQueue->submissions.size() + 1;
447051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->signaled = true;
447151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->in_use.fetch_add(1);
447251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                semaphore_signals.push_back(semaphore);
447351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            }
447451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        }
447551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        for (uint32_t i = 0; i < submit->commandBufferCount; i++) {
447651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            auto cb_node = GetCBNode(dev_data, submit->pCommandBuffers[i]);
447751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            if (cb_node) {
447851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                cbs.push_back(submit->pCommandBuffers[i]);
447951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                for (auto secondaryCmdBuffer : cb_node->secondaryCommandBuffers) {
448051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    cbs.push_back(secondaryCmdBuffer);
448151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                }
448251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                UpdateCmdBufImageLayouts(dev_data, cb_node);
448351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                incrementResources(dev_data, cb_node);
448451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                if (!cb_node->secondaryCommandBuffers.empty()) {
448551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    for (auto secondaryCmdBuffer : cb_node->secondaryCommandBuffers) {
448651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                        GLOBAL_CB_NODE *pSubCB = GetCBNode(dev_data, secondaryCmdBuffer);
448751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                        incrementResources(dev_data, pSubCB);
448851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    }
448951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                }
449051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            }
449151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        }
449251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        pQueue->submissions.emplace_back(cbs, semaphore_waits, semaphore_signals,
449351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                                         submit_idx == submitCount - 1 ? fence : VK_NULL_HANDLE);
449451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    }
449551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
449651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    if (pFence && !submitCount) {
449751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        // If no submissions, but just dropping a fence on the end of the queue,
449851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        // record an empty submission with just the fence, so we can determine
449951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        // its completion.
450051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        pQueue->submissions.emplace_back(std::vector<VkCommandBuffer>(), std::vector<SEMAPHORE_WAIT>(), std::vector<VkSemaphore>(),
450151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                                         fence);
450251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    }
450351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour}
450451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
450551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic bool PreCallValidateQueueSubmit(layer_data *dev_data, VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits,
450651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                                       VkFence fence) {
450751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    auto pFence = GetFenceNode(dev_data, fence);
450851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    bool skip_call = ValidateFenceForSubmit(dev_data, pFence);
450951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    if (skip_call) {
451051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        return true;
451151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    }
451251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
451351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    unordered_set<VkSemaphore> signaled_semaphores;
451451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    unordered_set<VkSemaphore> unsignaled_semaphores;
451551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    vector<VkCommandBuffer> current_cmds;
451651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> localImageLayoutMap = dev_data->imageLayoutMap;
451751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    // Now verify each individual submit
451851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
451951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        const VkSubmitInfo *submit = &pSubmits[submit_idx];
452051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        for (uint32_t i = 0; i < submit->waitSemaphoreCount; ++i) {
4521208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis            skip_call |= ValidateStageMaskGsTsEnables(dev_data, submit->pWaitDstStageMask[i], "vkQueueSubmit()",
4522208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                                                      VALIDATION_ERROR_00142, VALIDATION_ERROR_00143);
452301a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            VkSemaphore semaphore = submit->pWaitSemaphores[i];
45249a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
452501a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            if (pSemaphore) {
452651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                if (unsignaled_semaphores.count(semaphore) ||
4527440bdd357701497c3442e3515f12ac1cfffc180aTony Barbour                    (!(signaled_semaphores.count(semaphore)) && !(pSemaphore->signaled))) {
452883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |=
45291344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
45301344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                                reinterpret_cast<const uint64_t &>(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
4531226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                "Queue 0x%p is waiting on semaphore 0x%" PRIx64 " that has no way to be signaled.", queue,
4532226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                reinterpret_cast<const uint64_t &>(semaphore));
453351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                } else {
453451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    signaled_semaphores.erase(semaphore);
453551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    unsignaled_semaphores.insert(semaphore);
45361344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                }
45375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
45385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
45395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < submit->signalSemaphoreCount; ++i) {
454001a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            VkSemaphore semaphore = submit->pSignalSemaphores[i];
45419a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
454201a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            if (pSemaphore) {
4543440bdd357701497c3442e3515f12ac1cfffc180aTony Barbour                if (signaled_semaphores.count(semaphore) || (!(unsignaled_semaphores.count(semaphore)) && pSemaphore->signaled)) {
454483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |=
45451344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
45461344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                                reinterpret_cast<const uint64_t &>(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
4547226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                "Queue 0x%p is signaling semaphore 0x%" PRIx64
4548414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                                " that has already been signaled but not waited on by queue 0x%" PRIx64 ".",
4549226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                queue, reinterpret_cast<const uint64_t &>(semaphore),
45509867daedbf52debc77d6568162ee21e071699b80Chris Forbes                                reinterpret_cast<uint64_t &>(pSemaphore->signaler.first));
45511344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                } else {
455251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    unsignaled_semaphores.erase(semaphore);
455351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    signaled_semaphores.insert(semaphore);
45541344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                }
45550a32ed7bdf03e7bda914e03c0bfa6ebf400cdf5bMichael Lentine            }
45565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
45575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < submit->commandBufferCount; i++) {
45589a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto cb_node = GetCBNode(dev_data, submit->pCommandBuffers[i]);
455951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            skip_call |= ValidateCmdBufImageLayouts(dev_data, cb_node, localImageLayoutMap);
4560d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis            if (cb_node) {
456151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                current_cmds.push_back(submit->pCommandBuffers[i]);
456251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                skip_call |= validatePrimaryCommandBufferState(
456351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    dev_data, cb_node, (int)std::count(current_cmds.begin(), current_cmds.end(), submit->pCommandBuffers[i]));
4564d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                skip_call |= validateQueueFamilyIndices(dev_data, cb_node, queue);
456551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
4566ea371fa7c8c57edb4d1436e4570cf54f3fc0463fTobin Ehlis                // Potential early exit here as bad object state may crash in delayed function calls
456751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                if (skip_call) {
456851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    return true;
456951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                }
457051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
45711344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                // Call submit-time functions to validate/update state
4572d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                for (auto &function : cb_node->validate_functions) {
457383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |= function();
45741344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                }
4575d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                for (auto &function : cb_node->eventUpdates) {
457683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |= function(queue);
45771344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                }
4578d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                for (auto &function : cb_node->queryUpdates) {
457983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |= function(queue);
4580d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                }
45811344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis            }
45825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
45839867daedbf52debc77d6568162ee21e071699b80Chris Forbes    }
458451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    return skip_call;
458551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour}
45869867daedbf52debc77d6568162ee21e071699b80Chris Forbes
458751920949f887ce8d3666c73c28ff19a5d8325a37Tony BarbourVKAPI_ATTR VkResult VKAPI_CALL QueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence) {
458851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
458951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    std::unique_lock<std::mutex> lock(global_lock);
459051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
459151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    bool skip = PreCallValidateQueueSubmit(dev_data, queue, submitCount, pSubmits, fence);
4592b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
45935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4594440bdd357701497c3442e3515f12ac1cfffc180aTony Barbour    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
459551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
459651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    VkResult result = dev_data->dispatch_table.QueueSubmit(queue, submitCount, pSubmits, fence);
459751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
459851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    lock.lock();
459951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    PostCallRecordQueueSubmit(dev_data, queue, submitCount, pSubmits, fence);
460051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    lock.unlock();
46015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
46025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
46035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4604f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultzstatic bool PreCallValidateAllocateMemory(layer_data *dev_data) {
4605f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    bool skip = false;
4606f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    if (dev_data->memObjMap.size() >= dev_data->phys_dev_properties.properties.limits.maxMemoryAllocationCount) {
4607f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
4608f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz                        reinterpret_cast<const uint64_t &>(dev_data->device), __LINE__, VALIDATION_ERROR_00611, "MEM",
4609f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz                        "Number of currently valid memory objects is not less than the maximum allowed (%u). %s",
4610f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz                        dev_data->phys_dev_properties.properties.limits.maxMemoryAllocationCount,
4611f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz                        validation_error_map[VALIDATION_ERROR_00611]);
4612f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    }
4613f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    return skip;
4614f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz}
4615f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz
4616f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultzstatic void PostCallRecordAllocateMemory(layer_data *dev_data, const VkMemoryAllocateInfo *pAllocateInfo, VkDeviceMemory *pMemory) {
4617f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    add_mem_obj_info(dev_data, dev_data->device, *pMemory, pAllocateInfo);
4618f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    return;
4619f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz}
4620f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz
462189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL AllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo,
462289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                              const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory) {
4623f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
462456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
4625f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    std::unique_lock<std::mutex> lock(global_lock);
4626f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    bool skip = PreCallValidateAllocateMemory(dev_data);
4627f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    if (!skip) {
4628f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        lock.unlock();
4629f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        result = dev_data->dispatch_table.AllocateMemory(device, pAllocateInfo, pAllocator, pMemory);
4630f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        lock.lock();
4631f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        if (VK_SUCCESS == result) {
4632f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz            PostCallRecordAllocateMemory(dev_data, pAllocateInfo, pMemory);
4633f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        }
4634e12739a56d02ca2fb5f0273862668e7475a21a6cMark Lobodzinski    }
46355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
46365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
46375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4638177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis// For given obj node, if it is use, flag a validation error and return callback result, else return false
4639177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlisbool ValidateObjectNotInUse(const layer_data *dev_data, BASE_NODE *obj_node, VK_OBJECT obj_struct,
4640177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis                            UNIQUE_VALIDATION_ERROR_CODE error_code) {
4641cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.object_in_use) return false;
4642177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    bool skip = false;
4643177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    if (obj_node->in_use.load()) {
4644177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, obj_struct.type, obj_struct.handle, __LINE__,
4645177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis                        error_code, "DS", "Cannot delete %s 0x%" PRIx64 " that is currently in use by a command buffer. %s",
4646177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis                        object_type_to_string(obj_struct.type), obj_struct.handle, validation_error_map[error_code]);
4647177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    }
4648177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    return skip;
4649177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis}
46505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4651177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlisstatic bool PreCallValidateFreeMemory(layer_data *dev_data, VkDeviceMemory mem, DEVICE_MEM_INFO **mem_info, VK_OBJECT *obj_struct) {
46529a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *mem_info = GetMemObjInfo(dev_data, mem);
465394165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(mem), VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT};
4654cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.free_memory) return false;
4655177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    bool skip = false;
4656177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    if (*mem_info) {
4657177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *mem_info, *obj_struct, VALIDATION_ERROR_00620);
4658177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    }
4659177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    return skip;
4660177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis}
46615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4662177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlisstatic void PostCallRecordFreeMemory(layer_data *dev_data, VkDeviceMemory mem, DEVICE_MEM_INFO *mem_info, VK_OBJECT obj_struct) {
4663177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    // Clear mem binding for any bound objects
466447705d01140c9f1492885e6efc5fa262e7e1c6a0Tobin Ehlis    for (auto obj : mem_info->obj_bindings) {
466547705d01140c9f1492885e6efc5fa262e7e1c6a0Tobin Ehlis        log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, obj.type, obj.handle, __LINE__, MEMTRACK_FREED_MEM_REF,
466647705d01140c9f1492885e6efc5fa262e7e1c6a0Tobin Ehlis                "MEM", "VK Object 0x%" PRIxLEAST64 " still has a reference to mem obj 0x%" PRIxLEAST64, obj.handle,
466747705d01140c9f1492885e6efc5fa262e7e1c6a0Tobin Ehlis                (uint64_t)mem_info->mem);
466847705d01140c9f1492885e6efc5fa262e7e1c6a0Tobin Ehlis        switch (obj.type) {
4669cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT: {
46709a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto image_state = GetImageState(dev_data, reinterpret_cast<VkImage &>(obj.handle));
4671cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                assert(image_state);  // Any destroyed images should already be removed from bindings
4672cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                image_state->binding.mem = MEMORY_UNBOUND;
4673cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4674cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4675cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT: {
46769a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto buffer_state = GetBufferState(dev_data, reinterpret_cast<VkBuffer &>(obj.handle));
4677cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                assert(buffer_state);  // Any destroyed buffers should already be removed from bindings
4678cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                buffer_state->binding.mem = MEMORY_UNBOUND;
4679cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4680cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4681cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
4682cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // Should only have buffer or image objects bound to memory
4683cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                assert(0);
4684177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        }
4685177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    }
4686177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    // Any bound cmd buffers are now invalid
468739c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, mem_info->cb_bindings, obj_struct);
4688177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    dev_data->memObjMap.erase(mem);
4689177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis}
4690177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis
4691177063aac84fac6f4e650c2629a08b48be643f96Tobin EhlisVKAPI_ATTR void VKAPI_CALL FreeMemory(VkDevice device, VkDeviceMemory mem, const VkAllocationCallbacks *pAllocator) {
469256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
4693177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    DEVICE_MEM_INFO *mem_info = nullptr;
4694177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    VK_OBJECT obj_struct;
4695b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
4696177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    bool skip = PreCallValidateFreeMemory(dev_data, mem, &mem_info, &obj_struct);
4697177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    if (!skip) {
4698177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        lock.unlock();
4699177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        dev_data->dispatch_table.FreeMemory(device, mem, pAllocator);
4700177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        lock.lock();
4701405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (mem != VK_NULL_HANDLE) {
4702405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordFreeMemory(dev_data, mem, mem_info, obj_struct);
4703405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
470474243a735fe102b370237ddf80d3e6f7ec5246dbMark Mueller    }
47055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
47065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4707f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis// Validate that given Map memory range is valid. This means that the memory should not already be mapped,
4708f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis//  and that the size of the map range should be:
4709f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis//  1. Not zero
4710f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis//  2. Within the size of the memory allocation
471151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool ValidateMapMemRange(layer_data *dev_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size) {
471283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
47135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
47145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (size == 0) {
471551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        skip_call = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
471683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                            (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, "MEM",
471783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                            "VkMapMemory: Attempting to map memory range of size zero");
47185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
47195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
472051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto mem_element = dev_data->memObjMap.find(mem);
472151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (mem_element != dev_data->memObjMap.end()) {
472257fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        auto mem_info = mem_element->second.get();
47235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // It is an application error to call VkMapMemory on an object that is already mapped
4724de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        if (mem_info->mem_range.size != 0) {
472551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            skip_call = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
472683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, "MEM",
472783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                "VkMapMemory: Attempting to map memory on an already-mapped object 0x%" PRIxLEAST64, (uint64_t)mem);
47285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
47295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
47305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Validate that offset + size is within object's allocationSize
47315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (size == VK_WHOLE_SIZE) {
4732de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis            if (offset >= mem_info->alloc_info.allocationSize) {
473351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                skip_call =
473451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
473551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                            (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, "MEM",
473651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                            "Mapping Memory from 0x%" PRIx64 " to 0x%" PRIx64
473751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                            " with size of VK_WHOLE_SIZE oversteps total array size 0x%" PRIx64,
473851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                            offset, mem_info->alloc_info.allocationSize, mem_info->alloc_info.allocationSize);
47395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
47405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
4741de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis            if ((offset + size) > mem_info->alloc_info.allocationSize) {
4742f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                skip_call = log_msg(
474351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
4744f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    (uint64_t)mem, __LINE__, VALIDATION_ERROR_00628, "MEM",
4745f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    "Mapping Memory from 0x%" PRIx64 " to 0x%" PRIx64 " oversteps total array size 0x%" PRIx64 ". %s", offset,
4746f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    size + offset, mem_info->alloc_info.allocationSize, validation_error_map[VALIDATION_ERROR_00628]);
47475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
47485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
47495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
475083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
47515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
47525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
475351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void storeMemRanges(layer_data *dev_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size) {
47549a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto mem_info = GetMemObjInfo(dev_data, mem);
475557fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    if (mem_info) {
4756de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        mem_info->mem_range.offset = offset;
4757de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        mem_info->mem_range.size = size;
47585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
47595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
47605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
476151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool deleteMemRanges(layer_data *dev_data, VkDeviceMemory mem) {
476283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
47639a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto mem_info = GetMemObjInfo(dev_data, mem);
476457fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    if (mem_info) {
4765de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        if (!mem_info->mem_range.size) {
47665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Valid Usage: memory must currently be mapped
476751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            skip_call = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
4768f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                                (uint64_t)mem, __LINE__, VALIDATION_ERROR_00649, "MEM",
4769f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                                "Unmapping Memory without memory being mapped: mem obj 0x%" PRIxLEAST64 ". %s", (uint64_t)mem,
4770f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                                validation_error_map[VALIDATION_ERROR_00649]);
47715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
4772de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        mem_info->mem_range.size = 0;
47735f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski        if (mem_info->shadow_copy) {
47745f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            free(mem_info->shadow_copy_base);
47755f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_copy_base = 0;
47765f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_copy = 0;
47775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
47785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
477983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
47805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
47815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
47825f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski// Guard value for pad data
47835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic char NoncoherentMemoryFillValue = 0xb;
47845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
47855f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinskistatic void initializeAndTrackMemory(layer_data *dev_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size,
47865f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                     void **ppData) {
47879a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto mem_info = GetMemObjInfo(dev_data, mem);
478857fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    if (mem_info) {
4789de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        mem_info->p_driver_data = *ppData;
4790de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        uint32_t index = mem_info->alloc_info.memoryTypeIndex;
4791b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis        if (dev_data->phys_dev_mem_props.memoryTypes[index].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) {
47925f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_copy = 0;
47935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
47945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (size == VK_WHOLE_SIZE) {
47955f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                size = mem_info->alloc_info.allocationSize - offset;
47965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
47975f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_pad_size = dev_data->phys_dev_properties.properties.limits.minMemoryMapAlignment;
47985f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            assert(vk_safe_modulo(mem_info->shadow_pad_size,
47995f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                  dev_data->phys_dev_properties.properties.limits.minMemoryMapAlignment) == 0);
48005f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            // Ensure start of mapped region reflects hardware alignment constraints
48015f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            uint64_t map_alignment = dev_data->phys_dev_properties.properties.limits.minMemoryMapAlignment;
48025f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski
48035f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            // From spec: (ppData - offset) must be aligned to at least limits::minMemoryMapAlignment.
48045f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            uint64_t start_offset = offset % map_alignment;
48055f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            // Data passed to driver will be wrapped by a guardband of data to detect over- or under-writes.
4806bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            mem_info->shadow_copy_base =
4807bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                malloc(static_cast<size_t>(2 * mem_info->shadow_pad_size + size + map_alignment + start_offset));
48085f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski
48095f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_copy =
48105f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                reinterpret_cast<char *>((reinterpret_cast<uintptr_t>(mem_info->shadow_copy_base) + map_alignment) &
4811bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         ~(map_alignment - 1)) +
4812bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                start_offset;
48135f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            assert(vk_safe_modulo(reinterpret_cast<uintptr_t>(mem_info->shadow_copy) + mem_info->shadow_pad_size - start_offset,
48145f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                  map_alignment) == 0);
48155f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski
48166e17c244b21ce43ac57404a00a0d844039eed363Mark Lobodzinski            memset(mem_info->shadow_copy, NoncoherentMemoryFillValue, static_cast<size_t>(2 * mem_info->shadow_pad_size + size));
48175f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            *ppData = static_cast<char *>(mem_info->shadow_copy) + mem_info->shadow_pad_size;
48185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
48195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
48205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
48215f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski
4822a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis// Verify that state for fence being waited on is appropriate. That is,
48239867daedbf52debc77d6568162ee21e071699b80Chris Forbes//  a fence being waited on should not already be signaled and
4824a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis//  it should have been submitted on a queue or during acquire next image
482549f6132af865afd5b7f413c91125971ac97c135aChris Forbesstatic inline bool verifyWaitFenceState(layer_data *dev_data, VkFence fence, const char *apiCall) {
482683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
48279b48b44dd917f95b5f34dd629ec4076fc87eb3a2Chris Forbes
48289a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pFence = GetFenceNode(dev_data, fence);
48299b48b44dd917f95b5f34dd629ec4076fc87eb3a2Chris Forbes    if (pFence) {
4830cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes        if (pFence->state == FENCE_UNSIGNALED) {
483183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
483283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 reinterpret_cast<uint64_t &>(fence), __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM",
4833cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "%s called for fence 0x%" PRIxLEAST64
4834cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 " which has not been submitted on a Queue or during "
483583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 "acquire next image.",
483683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 apiCall, reinterpret_cast<uint64_t &>(fence));
48375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
48385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
483983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
48405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
4841a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis
4842b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlisstatic void RetireFence(layer_data *dev_data, VkFence fence) {
48439a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pFence = GetFenceNode(dev_data, fence);
4844b3ecd4c1fb44a2e65dfc13256afa9150aabde1d4Chris Forbes    if (pFence->signaler.first != VK_NULL_HANDLE) {
484525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Fence signaller is a queue -- use this as proof that prior operations on that queue have completed.
48469a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        RetireWorkOnQueue(dev_data, GetQueueState(dev_data, pFence->signaler.first), pFence->signaler.second);
4847bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    } else {
484825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Fence signaller is the WSI. We're not tracking what the WSI op actually /was/ in CV yet, but we need to mark
484925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // the fence as retired.
4850d4513979120463171eb479cdded9336eb9944da1Chris Forbes        pFence->state = FENCE_RETIRED;
4851d4513979120463171eb479cdded9336eb9944da1Chris Forbes    }
4852b3ecd4c1fb44a2e65dfc13256afa9150aabde1d4Chris Forbes}
4853b3ecd4c1fb44a2e65dfc13256afa9150aabde1d4Chris Forbes
4854accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlisstatic bool PreCallValidateWaitForFences(layer_data *dev_data, uint32_t fence_count, const VkFence *fences) {
4855cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.wait_for_fences) return false;
4856accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    bool skip = false;
4857accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    for (uint32_t i = 0; i < fence_count; i++) {
4858accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis        skip |= verifyWaitFenceState(dev_data, fences[i], "vkWaitForFences");
4859b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis        skip |= VerifyQueueStateToFence(dev_data, fences[i]);
4860accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    }
4861accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    return skip;
4862accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis}
4863accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis
4864b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlisstatic void PostCallRecordWaitForFences(layer_data *dev_data, uint32_t fence_count, const VkFence *fences, VkBool32 wait_all) {
4865b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    // When we know that all fences are complete we can clean/remove their CBs
4866accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    if ((VK_TRUE == wait_all) || (1 == fence_count)) {
4867accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis        for (uint32_t i = 0; i < fence_count; i++) {
4868b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis            RetireFence(dev_data, fences[i]);
4869accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis        }
4870accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    }
4871accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    // NOTE : Alternate case not handled here is when some fences have completed. In
4872accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    //  this case for app to guarantee which fences completed it will have to call
4873b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    //  vkGetFenceStatus() at which point we'll clean/remove their CBs if complete.
4874accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis}
4875accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis
4876bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL WaitForFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences, VkBool32 waitAll,
4877bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                             uint64_t timeout) {
487856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
48795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Verify fence status of submitted fences
4880b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
4881accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    bool skip = PreCallValidateWaitForFences(dev_data, fenceCount, pFences);
4882b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
4883cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
4884a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis
48854a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.WaitForFences(device, fenceCount, pFences, waitAll, timeout);
4886414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller
48875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
4888b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
4889b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis        PostCallRecordWaitForFences(dev_data, fenceCount, pFences, waitAll);
4890b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
48915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
48925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
48935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
48945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4895f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlisstatic bool PreCallValidateGetFenceStatus(layer_data *dev_data, VkFence fence) {
4896cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.get_fence_state) return false;
4897f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis    return verifyWaitFenceState(dev_data, fence, "vkGetFenceStatus");
4898f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis}
4899f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis
4900b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlisstatic void PostCallRecordGetFenceStatus(layer_data *dev_data, VkFence fence) { RetireFence(dev_data, fence); }
4901f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis
490289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL GetFenceStatus(VkDevice device, VkFence fence) {
490356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
4904b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
4905f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis    bool skip = PreCallValidateGetFenceStatus(dev_data, fence);
4906b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
4907cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
4908a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis
49094a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.GetFenceStatus(device, fence);
49105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
4911f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis        lock.lock();
4912b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis        PostCallRecordGetFenceStatus(dev_data, fence);
4913f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis        lock.unlock();
49145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
49155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
49165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
49175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
49183b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlisstatic void PostCallRecordGetDeviceQueue(layer_data *dev_data, uint32_t q_family_index, VkQueue queue) {
49193b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    // Add queue to tracking set only if it is new
49203b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    auto result = dev_data->queues.emplace(queue);
49213b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    if (result.second == true) {
492236c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlis        QUEUE_STATE *queue_state = &dev_data->queueMap[queue];
49233b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis        queue_state->queue = queue;
49243b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis        queue_state->queueFamilyIndex = q_family_index;
49253b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis        queue_state->seq = 0;
49263b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    }
49273b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis}
49283b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis
4929bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL GetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue *pQueue) {
493056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
49314a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.GetDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue);
4932b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::lock_guard<std::mutex> lock(global_lock);
4933b376edacad6f7ab3fcc0a914e9b1673a9fcd5143Mark Lobodzinski
49343b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    PostCallRecordGetDeviceQueue(dev_data, queueFamilyIndex, *pQueue);
49355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
49365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
493736c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic bool PreCallValidateQueueWaitIdle(layer_data *dev_data, VkQueue queue, QUEUE_STATE **queue_state) {
49389a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *queue_state = GetQueueState(dev_data, queue);
4939cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.queue_wait_idle) return false;
4940e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis    return VerifyQueueStateToSeq(dev_data, *queue_state, (*queue_state)->seq + (*queue_state)->submissions.size());
49414273a1c157585a645dca4c960086032793899d05Tobin Ehlis}
49424273a1c157585a645dca4c960086032793899d05Tobin Ehlis
494336c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic void PostCallRecordQueueWaitIdle(layer_data *dev_data, QUEUE_STATE *queue_state) {
4944e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis    RetireWorkOnQueue(dev_data, queue_state, queue_state->seq + queue_state->submissions.size());
49454273a1c157585a645dca4c960086032793899d05Tobin Ehlis}
49464273a1c157585a645dca4c960086032793899d05Tobin Ehlis
494789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL QueueWaitIdle(VkQueue queue) {
494856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
494936c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlis    QUEUE_STATE *queue_state = nullptr;
49509867daedbf52debc77d6568162ee21e071699b80Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
49514273a1c157585a645dca4c960086032793899d05Tobin Ehlis    bool skip = PreCallValidateQueueWaitIdle(dev_data, queue, &queue_state);
49529867daedbf52debc77d6568162ee21e071699b80Chris Forbes    lock.unlock();
4953cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
49544a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.QueueWaitIdle(queue);
49554273a1c157585a645dca4c960086032793899d05Tobin Ehlis    if (VK_SUCCESS == result) {
4956e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis        lock.lock();
4957e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis        PostCallRecordQueueWaitIdle(dev_data, queue_state);
4958e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis        lock.unlock();
49594273a1c157585a645dca4c960086032793899d05Tobin Ehlis    }
49605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
49615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
49625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
49638767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlisstatic bool PreCallValidateDeviceWaitIdle(layer_data *dev_data) {
4964cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.device_wait_idle) return false;
49658767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    bool skip = false;
49668767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    for (auto &queue : dev_data->queueMap) {
49678767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        skip |= VerifyQueueStateToSeq(dev_data, &queue.second, queue.second.seq + queue.second.submissions.size());
49688767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    }
49698767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    return skip;
49708767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis}
49718767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis
49728767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlisstatic void PostCallRecordDeviceWaitIdle(layer_data *dev_data) {
49738767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    for (auto &queue : dev_data->queueMap) {
49748767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        RetireWorkOnQueue(dev_data, &queue.second, queue.second.seq + queue.second.submissions.size());
49758767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    }
49768767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis}
49778767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis
497889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL DeviceWaitIdle(VkDevice device) {
497956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
4980b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
49818767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    bool skip = PreCallValidateDeviceWaitIdle(dev_data);
4982b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
4983cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
49844a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.DeviceWaitIdle(device);
49858767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    if (VK_SUCCESS == result) {
49868767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        lock.lock();
49878767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        PostCallRecordDeviceWaitIdle(dev_data);
49888767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        lock.unlock();
49898767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    }
49905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
49915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
49925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
49931d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlisstatic bool PreCallValidateDestroyFence(layer_data *dev_data, VkFence fence, FENCE_NODE **fence_node, VK_OBJECT *obj_struct) {
49949a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *fence_node = GetFenceNode(dev_data, fence);
49951d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(fence), VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT};
4996cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_fence) return false;
49971d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    bool skip = false;
49981d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    if (*fence_node) {
49991d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        if ((*fence_node)->state == FENCE_INFLIGHT) {
50001d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
5001208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                            (uint64_t)(fence), __LINE__, VALIDATION_ERROR_00173, "DS", "Fence 0x%" PRIx64 " is in use. %s",
5002208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                            (uint64_t)(fence), validation_error_map[VALIDATION_ERROR_00173]);
50031d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        }
50041d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    }
50051d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    return skip;
50061d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis}
50071d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis
50081d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlisstatic void PostCallRecordDestroyFence(layer_data *dev_data, VkFence fence) { dev_data->fenceMap.erase(fence); }
50091d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis
501089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL DestroyFence(VkDevice device, VkFence fence, const VkAllocationCallbacks *pAllocator) {
501156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
50121d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    // Common data objects used pre & post call
50131d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    FENCE_NODE *fence_node = nullptr;
50141d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    VK_OBJECT obj_struct;
5015b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
50161d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    bool skip = PreCallValidateDestroyFence(dev_data, fence, &fence_node, &obj_struct);
50171344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
50181d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    if (!skip) {
50191d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        lock.unlock();
50204a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyFence(device, fence, pAllocator);
50211d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        lock.lock();
50221d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        PostCallRecordDestroyFence(dev_data, fence);
50231d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    }
50245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
50255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5026c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlisstatic bool PreCallValidateDestroySemaphore(layer_data *dev_data, VkSemaphore semaphore, SEMAPHORE_NODE **sema_node,
5027c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis                                            VK_OBJECT *obj_struct) {
50289a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *sema_node = GetSemaphoreNode(dev_data, semaphore);
5029c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(semaphore), VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT};
5030cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_semaphore) return false;
5031c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    bool skip = false;
5032c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    if (*sema_node) {
5033c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *sema_node, *obj_struct, VALIDATION_ERROR_00199);
5034c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    }
5035c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    return skip;
5036c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis}
5037c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis
5038c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlisstatic void PostCallRecordDestroySemaphore(layer_data *dev_data, VkSemaphore sema) { dev_data->semaphoreMap.erase(sema); }
5039c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis
5040bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroySemaphore(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks *pAllocator) {
504156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5042c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    SEMAPHORE_NODE *sema_node;
5043c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    VK_OBJECT obj_struct;
5044e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
5045c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    bool skip = PreCallValidateDestroySemaphore(dev_data, semaphore, &sema_node, &obj_struct);
5046eafbf0b68ee6ea6e0bf33f07e0058d00a96efd9aTobin Ehlis    if (!skip) {
5047eafbf0b68ee6ea6e0bf33f07e0058d00a96efd9aTobin Ehlis        lock.unlock();
50484a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroySemaphore(device, semaphore, pAllocator);
5049c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis        lock.lock();
5050c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis        PostCallRecordDestroySemaphore(dev_data, semaphore);
505199d938c90c2f000ee73fb13513dacf84ffa5651fMark Mueller    }
50525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
50535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
50544710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlisstatic bool PreCallValidateDestroyEvent(layer_data *dev_data, VkEvent event, EVENT_STATE **event_state, VK_OBJECT *obj_struct) {
50559a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *event_state = GetEventNode(dev_data, event);
505694165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(event), VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT};
5057cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_event) return false;
5058d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    bool skip = false;
5059d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    if (*event_state) {
5060d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *event_state, *obj_struct, VALIDATION_ERROR_00213);
5061d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    }
5062d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    return skip;
5063d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis}
5064d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis
50654710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlisstatic void PostCallRecordDestroyEvent(layer_data *dev_data, VkEvent event, EVENT_STATE *event_state, VK_OBJECT obj_struct) {
506639c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, event_state->cb_bindings, obj_struct);
5067d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    dev_data->eventMap.erase(event);
5068d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis}
5069d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis
507089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL DestroyEvent(VkDevice device, VkEvent event, const VkAllocationCallbacks *pAllocator) {
507156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
50724710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis    EVENT_STATE *event_state = nullptr;
5073d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    VK_OBJECT obj_struct;
5074b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5075d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    bool skip = PreCallValidateDestroyEvent(dev_data, event, &event_state, &obj_struct);
5076f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    if (!skip) {
5077f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis        lock.unlock();
50784a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyEvent(device, event, pAllocator);
5079d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis        lock.lock();
5080405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (event != VK_NULL_HANDLE) {
5081405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyEvent(dev_data, event, event_state, obj_struct);
5082405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
5083f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    }
50845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
50855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
508683c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlisstatic bool PreCallValidateDestroyQueryPool(layer_data *dev_data, VkQueryPool query_pool, QUERY_POOL_NODE **qp_state,
508783c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis                                            VK_OBJECT *obj_struct) {
50889a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *qp_state = GetQueryPoolNode(dev_data, query_pool);
508983c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(query_pool), VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT};
5090cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_query_pool) return false;
509183c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    bool skip = false;
509283c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    if (*qp_state) {
509383c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *qp_state, *obj_struct, VALIDATION_ERROR_01012);
509483c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    }
509583c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    return skip;
509683c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis}
509783c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis
5098bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic void PostCallRecordDestroyQueryPool(layer_data *dev_data, VkQueryPool query_pool, QUERY_POOL_NODE *qp_state,
5099bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           VK_OBJECT obj_struct) {
510083c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    invalidateCommandBuffers(dev_data, qp_state->cb_bindings, obj_struct);
510183c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    dev_data->queryPoolMap.erase(query_pool);
510283c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis}
510383c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis
5104bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks *pAllocator) {
510556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
510683c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    QUERY_POOL_NODE *qp_state = nullptr;
510783c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    VK_OBJECT obj_struct;
5108ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
510983c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    bool skip = PreCallValidateDestroyQueryPool(dev_data, queryPool, &qp_state, &obj_struct);
5110f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    if (!skip) {
5111f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis        lock.unlock();
51124a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyQueryPool(device, queryPool, pAllocator);
511383c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis        lock.lock();
5114405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (queryPool != VK_NULL_HANDLE) {
5115405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyQueryPool(dev_data, queryPool, qp_state, obj_struct);
5116405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
5117f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    }
51185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
51199fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlisstatic bool PreCallValidateGetQueryPoolResults(layer_data *dev_data, VkQueryPool query_pool, uint32_t first_query,
51209fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                               uint32_t query_count, VkQueryResultFlags flags,
51219fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                               unordered_map<QueryObject, vector<VkCommandBuffer>> *queries_in_flight) {
51229fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    for (auto cmd_buffer : dev_data->globalInFlightCmdBuffers) {
51239a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto cb = GetCBNode(dev_data, cmd_buffer);
51249fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        for (auto query_state_pair : cb->queryToStateMap) {
51259fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            (*queries_in_flight)[query_state_pair.first].push_back(cmd_buffer);
51265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
51275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5128cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.get_query_pool_results) return false;
51299fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    bool skip = false;
51309fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    for (uint32_t i = 0; i < query_count; ++i) {
51319fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        QueryObject query = {query_pool, first_query + i};
51329fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        auto qif_pair = queries_in_flight->find(query);
51339fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        auto query_state_pair = dev_data->queryToStateMap.find(query);
51349fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        if (query_state_pair != dev_data->queryToStateMap.end()) {
5135ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski            // Available and in flight
51369fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            if (qif_pair != queries_in_flight->end() && query_state_pair != dev_data->queryToStateMap.end() &&
51379fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                query_state_pair->second) {
51389fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                for (auto cmd_buffer : qif_pair->second) {
51399a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto cb = GetCBNode(dev_data, cmd_buffer);
51409fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    auto query_event_pair = cb->waitedEventsBeforeQueryReset.find(query);
51419fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    if (query_event_pair == cb->waitedEventsBeforeQueryReset.end()) {
51429fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
51439fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                        VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
51449fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                        "Cannot get query results on queryPool 0x%" PRIx64 " with index %d which is in flight.",
51459fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                        (uint64_t)(query_pool), first_query + i);
5146ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                    }
5147ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                }
5148ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                // Unavailable and in flight
51499fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            } else if (qif_pair != queries_in_flight->end() && query_state_pair != dev_data->queryToStateMap.end() &&
51509fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                       !query_state_pair->second) {
5151ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                // TODO : Can there be the same query in use by multiple command buffers in flight?
5152ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                bool make_available = false;
51539fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                for (auto cmd_buffer : qif_pair->second) {
51549a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto cb = GetCBNode(dev_data, cmd_buffer);
51559fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    make_available |= cb->queryToStateMap[query];
5156ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                }
5157ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                if (!(((flags & VK_QUERY_RESULT_PARTIAL_BIT) || (flags & VK_QUERY_RESULT_WAIT_BIT)) && make_available)) {
51589fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
51599fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                    VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
51609fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                    "Cannot get query results on queryPool 0x%" PRIx64 " with index %d which is unavailable.",
51619fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                    (uint64_t)(query_pool), first_query + i);
51625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
5163ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                // Unavailable
51649fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            } else if (query_state_pair != dev_data->queryToStateMap.end() && !query_state_pair->second) {
51659fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0,
51669fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
51679fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                "Cannot get query results on queryPool 0x%" PRIx64 " with index %d which is unavailable.",
51689fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                (uint64_t)(query_pool), first_query + i);
51699fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                // Uninitialized
51709fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            } else if (query_state_pair == dev_data->queryToStateMap.end()) {
51719fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0,
51729fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
51739fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                "Cannot get query results on queryPool 0x%" PRIx64
51749fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                " with index %d as data has not been collected for this index.",
51759fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                (uint64_t)(query_pool), first_query + i);
51765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
51775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
51785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
51799fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    return skip;
51809fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis}
51819fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis
51829fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlisstatic void PostCallRecordGetQueryPoolResults(layer_data *dev_data, VkQueryPool query_pool, uint32_t first_query,
51839fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                              uint32_t query_count,
51849fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                              unordered_map<QueryObject, vector<VkCommandBuffer>> *queries_in_flight) {
51859fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    for (uint32_t i = 0; i < query_count; ++i) {
51869fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        QueryObject query = {query_pool, first_query + i};
51879fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        auto qif_pair = queries_in_flight->find(query);
51889fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        auto query_state_pair = dev_data->queryToStateMap.find(query);
51899fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        if (query_state_pair != dev_data->queryToStateMap.end()) {
51909fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            // Available and in flight
51919fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            if (qif_pair != queries_in_flight->end() && query_state_pair != dev_data->queryToStateMap.end() &&
51929fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                query_state_pair->second) {
51939fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                for (auto cmd_buffer : qif_pair->second) {
51949a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto cb = GetCBNode(dev_data, cmd_buffer);
51959fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    auto query_event_pair = cb->waitedEventsBeforeQueryReset.find(query);
51969fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    if (query_event_pair != cb->waitedEventsBeforeQueryReset.end()) {
51979fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                        for (auto event : query_event_pair->second) {
51989fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                            dev_data->eventMap[event].needsSignaled = true;
51999fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                        }
52009fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    }
52019fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                }
52029fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            }
52039fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        }
52049fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    }
52059fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis}
52069fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis
52079fdee42cd357379efb9aa27f90beb75d1f824955Tobin EhlisVKAPI_ATTR VkResult VKAPI_CALL GetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount,
52089fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                                   size_t dataSize, void *pData, VkDeviceSize stride, VkQueryResultFlags flags) {
520956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
52109fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    unordered_map<QueryObject, vector<VkCommandBuffer>> queries_in_flight;
52119fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
52129fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    bool skip = PreCallValidateGetQueryPoolResults(dev_data, queryPool, firstQuery, queryCount, flags, &queries_in_flight);
5213b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
5214cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
52159fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    VkResult result =
52169fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        dev_data->dispatch_table.GetQueryPoolResults(device, queryPool, firstQuery, queryCount, dataSize, pData, stride, flags);
52179fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    lock.lock();
52189fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    PostCallRecordGetQueryPoolResults(dev_data, queryPool, firstQuery, queryCount, &queries_in_flight);
52199fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    lock.unlock();
52209fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    return result;
52215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
52225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5223825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Return true if given ranges intersect, else false
5224825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Prereq : For both ranges, range->end - range->start > 0. This case should have already resulted
5225825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  in an error so not checking that here
5226825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// pad_ranges bool indicates a linear and non-linear comparison which requires padding
5227825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// In the case where padding is required, if an alias is encountered then a validation error is reported and skip_call
5228825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  may be set by the callback function so caller should merge in skip_call value if padding case is possible.
52297dc3fbb89e2dcf3df8fc2e6639a867a959fef3f3Tobin Ehlisstatic bool rangesIntersect(layer_data const *dev_data, MEMORY_RANGE const *range1, MEMORY_RANGE const *range2, bool *skip_call) {
52307dc3fbb89e2dcf3df8fc2e6639a867a959fef3f3Tobin Ehlis    *skip_call = false;
5231825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto r1_start = range1->start;
5232825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto r1_end = range1->end;
5233825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto r2_start = range2->start;
5234825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto r2_end = range2->end;
5235825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    VkDeviceSize pad_align = 1;
5236825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    if (range1->linear != range2->linear) {
5237825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        pad_align = dev_data->phys_dev_properties.properties.limits.bufferImageGranularity;
5238825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    }
5239cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if ((r1_end & ~(pad_align - 1)) < (r2_start & ~(pad_align - 1))) return false;
5240cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if ((r1_start & ~(pad_align - 1)) > (r2_end & ~(pad_align - 1))) return false;
524147aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
5242825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    if (range1->linear != range2->linear) {
524353ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis        // In linear vs. non-linear case, warn of aliasing
5244825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        const char *r1_linear_str = range1->linear ? "Linear" : "Non-linear";
5245825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        const char *r1_type_str = range1->image ? "image" : "buffer";
5246825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        const char *r2_linear_str = range2->linear ? "linear" : "non-linear";
5247825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        const char *r2_type_str = range2->image ? "image" : "buffer";
5248825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        auto obj_type = range1->image ? VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT : VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT;
524953ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis        *skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, obj_type, range1->handle, 0,
525053ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis                              MEMTRACK_INVALID_ALIASING, "MEM", "%s %s 0x%" PRIx64 " is aliased with %s %s 0x%" PRIx64
525153ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis                                                                " which may indicate a bug. For further info refer to the "
525253ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis                                                                "Buffer-Image Granularity section of the Vulkan specification. "
525353ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis                                                                "(https://www.khronos.org/registry/vulkan/specs/1.0-extensions/"
525453ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis                                                                "xhtml/vkspec.html#resources-bufferimagegranularity)",
525553ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis                              r1_linear_str, r1_type_str, range1->handle, r2_linear_str, r2_type_str, range2->handle);
525647aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    }
5257825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    // Ranges intersect
5258825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    return true;
525947aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski}
5260623548a271287ae55415e45e3c654ee66d4e79ffTobin Ehlis// Simplified rangesIntersect that calls above function to check range1 for intersection with offset & end addresses
5261c3340a06ecac4d7b9540592cae339f8fc224d0b1Mark Lobodzinskibool rangesIntersect(layer_data const *dev_data, MEMORY_RANGE const *range1, VkDeviceSize offset, VkDeviceSize end) {
5262825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    // Create a local MEMORY_RANGE struct to wrap offset/size
5263825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    MEMORY_RANGE range_wrap;
5264825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    // Synch linear with range1 to avoid padding and potential validation error case
5265825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range_wrap.linear = range1->linear;
5266825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range_wrap.start = offset;
5267cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    range_wrap.end = end;
5268825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    bool tmp_bool;
52697dc3fbb89e2dcf3df8fc2e6639a867a959fef3f3Tobin Ehlis    return rangesIntersect(dev_data, range1, &range_wrap, &tmp_bool);
5270825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis}
5271cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis// For given mem_info, set all ranges valid that intersect [offset-end] range
5272cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis// TODO : For ranges where there is no alias, we may want to create new buffer ranges that are valid
5273cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlisstatic void SetMemRangesValid(layer_data const *dev_data, DEVICE_MEM_INFO *mem_info, VkDeviceSize offset, VkDeviceSize end) {
5274cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    bool tmp_bool = false;
5275f6e16b28b808a342cb92768001afa2cfeee08a11Tobin Ehlis    MEMORY_RANGE map_range = {};
5276cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    map_range.linear = true;
5277cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    map_range.start = offset;
5278cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    map_range.end = end;
5279cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    for (auto &handle_range_pair : mem_info->bound_ranges) {
52807dc3fbb89e2dcf3df8fc2e6639a867a959fef3f3Tobin Ehlis        if (rangesIntersect(dev_data, &handle_range_pair.second, &map_range, &tmp_bool)) {
5281cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis            // TODO : WARN here if tmp_bool true?
5282cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis            handle_range_pair.second.valid = true;
5283cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis        }
5284cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    }
5285cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis}
5286825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Object with given handle is being bound to memory w/ given mem_info struct.
5287825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  Track the newly bound memory range with given memoryOffset
5288825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  Also scan any previous ranges, track aliased ranges with new range, and flag an error if a linear
5289825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  and non-linear range incorrectly overlap.
5290825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Return true if an error is flagged and the user callback returns "true", otherwise false
5291825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// is_image indicates an image object, otherwise handle is for a buffer
5292825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// is_linear indicates a buffer or linear image
52937992c34b28dd617787f0e4d34fd023f894495edbCort Stratton// api_name API entry point that triggered this call
5294825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlisstatic bool InsertMemoryRange(layer_data const *dev_data, uint64_t handle, DEVICE_MEM_INFO *mem_info, VkDeviceSize memoryOffset,
52957992c34b28dd617787f0e4d34fd023f894495edbCort Stratton                              VkMemoryRequirements memRequirements, bool is_image, bool is_linear, const char *api_name) {
5296825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    bool skip_call = false;
52975360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    MEMORY_RANGE range;
5298825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
52997992c34b28dd617787f0e4d34fd023f894495edbCort Stratton    if (memoryOffset >= mem_info->alloc_info.allocationSize) {
53007992c34b28dd617787f0e4d34fd023f894495edbCort Stratton        UNIQUE_VALIDATION_ERROR_CODE error_code = is_image ? VALIDATION_ERROR_00805 : VALIDATION_ERROR_00793;
53017992c34b28dd617787f0e4d34fd023f894495edbCort Stratton        skip_call =
53027992c34b28dd617787f0e4d34fd023f894495edbCort Stratton            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
53037992c34b28dd617787f0e4d34fd023f894495edbCort Stratton                    reinterpret_cast<uint64_t &>(mem_info->mem), __LINE__, error_code, "MEM",
53047992c34b28dd617787f0e4d34fd023f894495edbCort Stratton                    "In %s, attempting to bind memory (0x%" PRIxLEAST64 ") to object (0x%" PRIxLEAST64
53057992c34b28dd617787f0e4d34fd023f894495edbCort Stratton                    "), memoryOffset=0x%" PRIxLEAST64 " must be less than the memory allocation size 0x%" PRIxLEAST64 ". %s",
53067992c34b28dd617787f0e4d34fd023f894495edbCort Stratton                    api_name, reinterpret_cast<uint64_t &>(mem_info->mem), handle, memoryOffset,
53077992c34b28dd617787f0e4d34fd023f894495edbCort Stratton                    mem_info->alloc_info.allocationSize, validation_error_map[error_code]);
53087992c34b28dd617787f0e4d34fd023f894495edbCort Stratton    }
53097992c34b28dd617787f0e4d34fd023f894495edbCort Stratton
5310825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range.image = is_image;
531147aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    range.handle = handle;
5312825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range.linear = is_linear;
5313f541bf53dee6daf82a4c8304354eac599a884d29Tobin Ehlis    range.valid = mem_info->global_valid;
5314825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range.memory = mem_info->mem;
531547aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    range.start = memoryOffset;
5316825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range.size = memRequirements.size;
531747aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    range.end = memoryOffset + memRequirements.size - 1;
53185360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    range.aliases.clear();
53195360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    // Update Memory aliasing
532075f4c8cec0996021a4258b9bf920a9e0fea4eac1Tobin 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
53215360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    // inserted into map before loop to get the final ptr, then we may enter loop when not needed & we check range against itself
53225360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    std::unordered_set<MEMORY_RANGE *> tmp_alias_ranges;
5323825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    for (auto &obj_range_pair : mem_info->bound_ranges) {
5324825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        auto check_range = &obj_range_pair.second;
53255360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis        bool intersection_error = false;
53267dc3fbb89e2dcf3df8fc2e6639a867a959fef3f3Tobin Ehlis        if (rangesIntersect(dev_data, &range, check_range, &intersection_error)) {
5327825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis            skip_call |= intersection_error;
5328825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis            range.aliases.insert(check_range);
53295360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis            tmp_alias_ranges.insert(check_range);
5330825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        }
5331825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    }
53325360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    mem_info->bound_ranges[handle] = std::move(range);
53335360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    for (auto tmp_range : tmp_alias_ranges) {
53345360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis        tmp_range->aliases.insert(&mem_info->bound_ranges[handle]);
53355360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    }
5336825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    if (is_image)
5337825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        mem_info->bound_images.insert(handle);
5338825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    else
5339825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        mem_info->bound_buffers.insert(handle);
5340825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
5341825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    return skip_call;
534247aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski}
534347aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
53449f12a235bb9c014878a98ce385b68587add2538aTobin Ehlisstatic bool InsertImageMemoryRange(layer_data const *dev_data, VkImage image, DEVICE_MEM_INFO *mem_info, VkDeviceSize mem_offset,
53457992c34b28dd617787f0e4d34fd023f894495edbCort Stratton                                   VkMemoryRequirements mem_reqs, bool is_linear, const char *api_name) {
53467992c34b28dd617787f0e4d34fd023f894495edbCort Stratton    return InsertMemoryRange(dev_data, reinterpret_cast<uint64_t &>(image), mem_info, mem_offset, mem_reqs, true, is_linear,
53477992c34b28dd617787f0e4d34fd023f894495edbCort Stratton                             api_name);
5348825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis}
5349825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
53509f12a235bb9c014878a98ce385b68587add2538aTobin Ehlisstatic bool InsertBufferMemoryRange(layer_data const *dev_data, VkBuffer buffer, DEVICE_MEM_INFO *mem_info, VkDeviceSize mem_offset,
53517992c34b28dd617787f0e4d34fd023f894495edbCort Stratton                                    VkMemoryRequirements mem_reqs, const char *api_name) {
53527992c34b28dd617787f0e4d34fd023f894495edbCort Stratton    return InsertMemoryRange(dev_data, reinterpret_cast<uint64_t &>(buffer), mem_info, mem_offset, mem_reqs, false, true, api_name);
5353825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis}
5354825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
5355825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Remove MEMORY_RANGE struct for give handle from bound_ranges of mem_info
5356825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  is_image indicates if handle is for image or buffer
5357825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  This function will also remove the handle-to-index mapping from the appropriate
5358825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  map and clean up any aliases for range being removed.
5359825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlisstatic void RemoveMemoryRange(uint64_t handle, DEVICE_MEM_INFO *mem_info, bool is_image) {
5360825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto erase_range = &mem_info->bound_ranges[handle];
5361825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    for (auto alias_range : erase_range->aliases) {
5362825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        alias_range->aliases.erase(erase_range);
536347aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    }
53645360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    erase_range->aliases.clear();
5365825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    mem_info->bound_ranges.erase(handle);
53661cba4e1b5940c6818572e05dcad5a3a47fafbc9eTobin Ehlis    if (is_image) {
5367825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        mem_info->bound_images.erase(handle);
53681cba4e1b5940c6818572e05dcad5a3a47fafbc9eTobin Ehlis    } else {
5369825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        mem_info->bound_buffers.erase(handle);
53701cba4e1b5940c6818572e05dcad5a3a47fafbc9eTobin Ehlis    }
537147aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski}
537247aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
5373842b2d28ded1c6e2c38491a81213d0e1d1b7295aMark Lobodzinskivoid RemoveBufferMemoryRange(uint64_t handle, DEVICE_MEM_INFO *mem_info) { RemoveMemoryRange(handle, mem_info, false); }
5374825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
53758c59133586421be878d393799b30044497f77727Mark Lobodzinskivoid RemoveImageMemoryRange(uint64_t handle, DEVICE_MEM_INFO *mem_info) { RemoveMemoryRange(handle, mem_info, true); }
5376825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
5377bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator) {
537856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5379e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    BUFFER_STATE *buffer_state = nullptr;
5380e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    VK_OBJECT obj_struct;
5381b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5382e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    bool skip = PreCallValidateDestroyBuffer(dev_data, buffer, &buffer_state, &obj_struct);
5383e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    if (!skip) {
5384b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
53854a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyBuffer(device, buffer, pAllocator);
5386e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis        lock.lock();
5387405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (buffer != VK_NULL_HANDLE) {
5388405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyBuffer(dev_data, buffer, buffer_state, obj_struct);
5389405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
539047aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    }
53915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
53925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5393bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyBufferView(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks *pAllocator) {
539456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5395f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    // Common data objects used pre & post call
53968e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    BUFFER_VIEW_STATE *buffer_view_state = nullptr;
53978e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    VK_OBJECT obj_struct;
5398a123662876eebfa844faa65ae3f071d3d77618ebTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
53998e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    // Validate state before calling down chain, update common data if we'll be calling down chain
54008e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    bool skip = PreCallValidateDestroyBufferView(dev_data, bufferView, &buffer_view_state, &obj_struct);
540138e26abbaa884eb48bfec4ddb4e0ae2c90634e06Tobin Ehlis    if (!skip) {
540238e26abbaa884eb48bfec4ddb4e0ae2c90634e06Tobin Ehlis        lock.unlock();
54034a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyBufferView(device, bufferView, pAllocator);
54048e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis        lock.lock();
5405405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (bufferView != VK_NULL_HANDLE) {
5406405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyBufferView(dev_data, bufferView, buffer_view_state, obj_struct);
5407405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
54085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
54095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
54105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
54112a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin EhlisVKAPI_ATTR void VKAPI_CALL DestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) {
541256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
54131facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    IMAGE_STATE *image_state = nullptr;
54142a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    VK_OBJECT obj_struct;
54152a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
54162a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    bool skip = PreCallValidateDestroyImage(dev_data, image, &image_state, &obj_struct);
54172a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    if (!skip) {
5418f940225c9e5e3e14b3f5a32d3ea360b585614600Tobin Ehlis        lock.unlock();
54194a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyImage(device, image, pAllocator);
54202a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis        lock.lock();
5421405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (image != VK_NULL_HANDLE) {
5422405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyImage(dev_data, image, image_state, obj_struct);
5423405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
54245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
54255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
54265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
54274261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinskistatic bool ValidateMemoryTypes(const layer_data *dev_data, const DEVICE_MEM_INFO *mem_info, const uint32_t memory_type_bits,
5428f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                                const char *funcName, UNIQUE_VALIDATION_ERROR_CODE msgCode) {
54294261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinski    bool skip_call = false;
5430de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis    if (((1 << mem_info->alloc_info.memoryTypeIndex) & memory_type_bits) == 0) {
5431f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen        skip_call =
5432f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
5433f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    reinterpret_cast<const uint64_t &>(mem_info->mem), __LINE__, msgCode, "MT",
5434f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    "%s(): MemoryRequirements->memoryTypeBits (0x%X) for this object type are not compatible with the memory "
5435f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    "type (0x%X) of this memory object 0x%" PRIx64 ". %s",
5436f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    funcName, memory_type_bits, mem_info->alloc_info.memoryTypeIndex,
5437f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    reinterpret_cast<const uint64_t &>(mem_info->mem), validation_error_map[msgCode]);
54384261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinski    }
54394261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinski    return skip_call;
54404261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinski}
54414261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinski
5442bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL BindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
544356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
54445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
5445b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
54465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Track objects tied to memory
54479f12a235bb9c014878a98ce385b68587add2538aTobin Ehlis    uint64_t buffer_handle = reinterpret_cast<uint64_t &>(buffer);
5448888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    bool skip_call = SetMemBinding(dev_data, mem, buffer_handle, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, "vkBindBufferMemory");
54499a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto buffer_state = GetBufferState(dev_data, buffer);
54505cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (buffer_state) {
54512eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        if (!buffer_state->memory_requirements_checked) {
54522eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            // There's not an explicit requirement in the spec to call vkGetBufferMemoryRequirements() prior to calling
54532eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            //  BindBufferMemory but it's implied in that memory being bound must conform with VkMemoryRequirements from
54542eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            //  vkGetBufferMemoryRequirements()
54552eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
54562eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis                                 buffer_handle, __LINE__, DRAWSTATE_INVALID_BUFFER, "DS",
54572eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis                                 "vkBindBufferMemory(): Binding memory to buffer 0x%" PRIxLEAST64
54582eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis                                 " but vkGetBufferMemoryRequirements() has not been called on that buffer.",
54592eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis                                 buffer_handle);
54602eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            // Make the call for them so we can verify the state
54612eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            lock.unlock();
54622eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            dev_data->dispatch_table.GetBufferMemoryRequirements(device, buffer, &buffer_state->requirements);
54632eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            lock.lock();
54642eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        }
54655cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        buffer_state->binding.mem = mem;
54665cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        buffer_state->binding.offset = memoryOffset;
54672eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        buffer_state->binding.size = buffer_state->requirements.size;
546847aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
546947aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski        // Track and validate bound memory range information
54709a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto mem_info = GetMemObjInfo(dev_data, mem);
547157fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        if (mem_info) {
54727992c34b28dd617787f0e4d34fd023f894495edbCort Stratton            skip_call |=
54737992c34b28dd617787f0e4d34fd023f894495edbCort Stratton                InsertBufferMemoryRange(dev_data, buffer, mem_info, memoryOffset, buffer_state->requirements, "vkBindBufferMemory");
54747992c34b28dd617787f0e4d34fd023f894495edbCort Stratton            skip_call |= ValidateMemoryTypes(dev_data, mem_info, buffer_state->requirements.memoryTypeBits, "vkBindBufferMemory",
5475f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                                             VALIDATION_ERROR_00797);
547647aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski        }
547747aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
54782c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves        // Validate memory requirements alignment
54792eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        if (vk_safe_modulo(memoryOffset, buffer_state->requirements.alignment) != 0) {
5480f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
5481f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                                 VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, VALIDATION_ERROR_02174, "DS",
5482cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "vkBindBufferMemory(): memoryOffset is 0x%" PRIxLEAST64
5483cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 " but must be an integer multiple of the "
5484f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                                 "VkMemoryRequirements::alignment value 0x%" PRIxLEAST64
5485f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                                 ", returned from a call to vkGetBufferMemoryRequirements with buffer. %s",
5486f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                                 memoryOffset, buffer_state->requirements.alignment, validation_error_map[VALIDATION_ERROR_02174]);
54872c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves        }
5488ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller
54892c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves        // Validate device limits alignments
5490ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller        static const VkBufferUsageFlagBits usage_list[3] = {
5491ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller            static_cast<VkBufferUsageFlagBits>(VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT),
5492bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT};
5493bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        static const char *memory_type[3] = {"texel", "uniform", "storage"};
5494bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        static const char *offset_name[3] = {"minTexelBufferOffsetAlignment", "minUniformBufferOffsetAlignment",
5495bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                             "minStorageBufferOffsetAlignment"};
5496cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski
5497cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        // TODO:  vk_validation_stats.py cannot abide braces immediately preceeding or following a validation error enum
5498cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        // clang-format off
5499cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        static const UNIQUE_VALIDATION_ERROR_CODE msgCode[3] = { VALIDATION_ERROR_00794, VALIDATION_ERROR_00795,
5500cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                                 VALIDATION_ERROR_00796 };
5501cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        // clang-format on
5502ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller
5503ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller        // Keep this one fresh!
5504ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller        const VkDeviceSize offset_requirement[3] = {
5505ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller            dev_data->phys_dev_properties.properties.limits.minTexelBufferOffsetAlignment,
5506ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller            dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment,
5507bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            dev_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment};
55088718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis        VkBufferUsageFlags usage = dev_data->bufferMap[buffer].get()->createInfo.usage;
5509ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller
5510ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller        for (int i = 0; i < 3; i++) {
5511ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller            if (usage & usage_list[i]) {
5512ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller                if (vk_safe_modulo(memoryOffset, offset_requirement[i]) != 0) {
5513cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip_call |= log_msg(
5514cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0,
5515cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        __LINE__, msgCode[i], "DS", "vkBindBufferMemory(): %s memoryOffset is 0x%" PRIxLEAST64
5516cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                    " but must be a multiple of "
5517cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                    "device limit %s 0x%" PRIxLEAST64 ". %s",
5518cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        memory_type[i], memoryOffset, offset_name[i], offset_requirement[i], validation_error_map[msgCode[i]]);
5519ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller                }
55202c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves            }
55212c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves        }
55225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5523b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
552483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (!skip_call) {
55254a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.BindBufferMemory(device, buffer, mem, memoryOffset);
55265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
55275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
55285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
55295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5530bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL GetBufferMemoryRequirements(VkDevice device, VkBuffer buffer,
5531bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                       VkMemoryRequirements *pMemoryRequirements) {
553256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
553315caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    dev_data->dispatch_table.GetBufferMemoryRequirements(device, buffer, pMemoryRequirements);
55349a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto buffer_state = GetBufferState(dev_data, buffer);
553515caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    if (buffer_state) {
553615caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis        buffer_state->requirements = *pMemoryRequirements;
55372eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        buffer_state->memory_requirements_checked = true;
553815caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    }
55395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
55405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5541bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL GetImageMemoryRequirements(VkDevice device, VkImage image, VkMemoryRequirements *pMemoryRequirements) {
554256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
554315caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    dev_data->dispatch_table.GetImageMemoryRequirements(device, image, pMemoryRequirements);
55449a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto image_state = GetImageState(dev_data, image);
554515caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    if (image_state) {
554615caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis        image_state->requirements = *pMemoryRequirements;
55472eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        image_state->memory_requirements_checked = true;
554815caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    }
55495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
5550593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
5551bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyImageView(VkDevice device, VkImageView imageView, const VkAllocationCallbacks *pAllocator) {
555256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5553f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    // Common data objects used pre & post call
5554f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    IMAGE_VIEW_STATE *image_view_state = nullptr;
5555f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    VK_OBJECT obj_struct;
5556a123662876eebfa844faa65ae3f071d3d77618ebTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
5557f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    bool skip = PreCallValidateDestroyImageView(dev_data, imageView, &image_view_state, &obj_struct);
5558d85c42a6c1d6ad7a6f684c5bd793aab482b7705cTobin Ehlis    if (!skip) {
5559d85c42a6c1d6ad7a6f684c5bd793aab482b7705cTobin Ehlis        lock.unlock();
55604a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyImageView(device, imageView, pAllocator);
5561f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis        lock.lock();
5562405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (imageView != VK_NULL_HANDLE) {
5563405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyImageView(dev_data, imageView, image_view_state, obj_struct);
5564405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
5565d85c42a6c1d6ad7a6f684c5bd793aab482b7705cTobin Ehlis    }
55665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
55675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5568bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyShaderModule(VkDevice device, VkShaderModule shaderModule,
5569bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                               const VkAllocationCallbacks *pAllocator) {
557056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5571918c283ac4f8c604b79abd0c8b5706d2a7352a34Chris Forbes
5572b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
557351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    dev_data->shaderModuleMap.erase(shaderModule);
5574b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
5575918c283ac4f8c604b79abd0c8b5706d2a7352a34Chris Forbes
557651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    dev_data->dispatch_table.DestroyShaderModule(device, shaderModule, pAllocator);
55775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
55785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
55794c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic bool PreCallValidateDestroyPipeline(layer_data *dev_data, VkPipeline pipeline, PIPELINE_STATE **pipeline_state,
55808bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis                                           VK_OBJECT *obj_struct) {
558194165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *pipeline_state = getPipelineState(dev_data, pipeline);
558294165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(pipeline), VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT};
5583cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_pipeline) return false;
55848bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    bool skip = false;
55858bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    if (*pipeline_state) {
55861803032f91d772ff3589c9f5a51ade5b299ba538Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *pipeline_state, *obj_struct, VALIDATION_ERROR_00555);
55878bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    }
55888bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    return skip;
55898bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis}
55908bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis
55914c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic void PostCallRecordDestroyPipeline(layer_data *dev_data, VkPipeline pipeline, PIPELINE_STATE *pipeline_state,
55928bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis                                          VK_OBJECT obj_struct) {
55938bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    // Any bound cmd buffers are now invalid
559439c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, pipeline_state->cb_bindings, obj_struct);
55958bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    dev_data->pipelineMap.erase(pipeline);
55968bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis}
55978bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis
5598bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyPipeline(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks *pAllocator) {
559956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
56004c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    PIPELINE_STATE *pipeline_state = nullptr;
56018bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    VK_OBJECT obj_struct;
5602e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
56038bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    bool skip = PreCallValidateDestroyPipeline(dev_data, pipeline, &pipeline_state, &obj_struct);
5604f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    if (!skip) {
5605f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis        lock.unlock();
56064a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyPipeline(device, pipeline, pAllocator);
56078bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis        lock.lock();
5608405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (pipeline != VK_NULL_HANDLE) {
5609405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyPipeline(dev_data, pipeline, pipeline_state, obj_struct);
5610405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
5611f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    }
56125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
56135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5614bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyPipelineLayout(VkDevice device, VkPipelineLayout pipelineLayout,
5615bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkAllocationCallbacks *pAllocator) {
561656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5617e28cddb35c63274c13873b9a7060ad43b255c6f1Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
56186792ea7cc0ce5fa64b7bd6c946460608cbda91c7Tobin Ehlis    dev_data->pipelineLayoutMap.erase(pipelineLayout);
5619e28cddb35c63274c13873b9a7060ad43b255c6f1Tobin Ehlis    lock.unlock();
5620e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis
56214a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.DestroyPipelineLayout(device, pipelineLayout, pAllocator);
56225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
56235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5624d31a44af6da568692a73201825459689c9431867Tobin Ehlisstatic bool PreCallValidateDestroySampler(layer_data *dev_data, VkSampler sampler, SAMPLER_STATE **sampler_state,
5625806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis                                          VK_OBJECT *obj_struct) {
56269a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *sampler_state = GetSamplerState(dev_data, sampler);
562794165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(sampler), VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT};
5628cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_sampler) return false;
5629806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    bool skip = false;
5630806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    if (*sampler_state) {
5631806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *sampler_state, *obj_struct, VALIDATION_ERROR_00837);
5632806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    }
5633806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    return skip;
5634806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis}
5635806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis
5636d31a44af6da568692a73201825459689c9431867Tobin Ehlisstatic void PostCallRecordDestroySampler(layer_data *dev_data, VkSampler sampler, SAMPLER_STATE *sampler_state,
5637806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis                                         VK_OBJECT obj_struct) {
5638806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    // Any bound cmd buffers are now invalid
5639cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (sampler_state) invalidateCommandBuffers(dev_data, sampler_state->cb_bindings, obj_struct);
5640806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    dev_data->samplerMap.erase(sampler);
5641806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis}
5642806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis
5643bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroySampler(VkDevice device, VkSampler sampler, const VkAllocationCallbacks *pAllocator) {
564456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5645d31a44af6da568692a73201825459689c9431867Tobin Ehlis    SAMPLER_STATE *sampler_state = nullptr;
5646806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    VK_OBJECT obj_struct;
564756f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
5648806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    bool skip = PreCallValidateDestroySampler(dev_data, sampler, &sampler_state, &obj_struct);
5649f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    if (!skip) {
5650f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis        lock.unlock();
56514a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroySampler(device, sampler, pAllocator);
5652806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis        lock.lock();
5653405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (sampler != VK_NULL_HANDLE) {
5654405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroySampler(dev_data, sampler, sampler_state, obj_struct);
5655405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
5656f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    }
56575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
56585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
565979c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlisstatic void PostCallRecordDestroyDescriptorSetLayout(layer_data *dev_data, VkDescriptorSetLayout ds_layout) {
566079c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis    dev_data->descriptorSetLayoutMap.erase(ds_layout);
566179c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis}
566279c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis
5663bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyDescriptorSetLayout(VkDevice device, VkDescriptorSetLayout descriptorSetLayout,
5664bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      const VkAllocationCallbacks *pAllocator) {
566556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
566679c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis    dev_data->dispatch_table.DestroyDescriptorSetLayout(device, descriptorSetLayout, pAllocator);
566779c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
566879c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis    PostCallRecordDestroyDescriptorSetLayout(dev_data, descriptorSetLayout);
56695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
56705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5671c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlisstatic bool PreCallValidateDestroyDescriptorPool(layer_data *dev_data, VkDescriptorPool pool,
5672a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis                                                 DESCRIPTOR_POOL_STATE **desc_pool_state, VK_OBJECT *obj_struct) {
56739a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *desc_pool_state = GetDescriptorPoolState(dev_data, pool);
567494165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(pool), VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT};
5675cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_descriptor_pool) return false;
5676c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    bool skip = false;
5677c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    if (*desc_pool_state) {
56781803032f91d772ff3589c9f5a51ade5b299ba538Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *desc_pool_state, *obj_struct, VALIDATION_ERROR_00901);
5679c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    }
5680c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    return skip;
5681c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis}
5682c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis
5683c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlisstatic void PostCallRecordDestroyDescriptorPool(layer_data *dev_data, VkDescriptorPool descriptorPool,
5684a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis                                                DESCRIPTOR_POOL_STATE *desc_pool_state, VK_OBJECT obj_struct) {
5685c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    // Any bound cmd buffers are now invalid
568639c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, desc_pool_state->cb_bindings, obj_struct);
5687c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    // Free sets that were in this pool
5688c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    for (auto ds : desc_pool_state->sets) {
5689c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis        freeDescriptorSet(dev_data, ds);
5690c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    }
5691c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    dev_data->descriptorPoolMap.erase(descriptorPool);
5692c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis}
5693c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis
5694bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool,
5695bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkAllocationCallbacks *pAllocator) {
569656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5697a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis    DESCRIPTOR_POOL_STATE *desc_pool_state = nullptr;
5698c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    VK_OBJECT obj_struct;
5699c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
5700c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    bool skip = PreCallValidateDestroyDescriptorPool(dev_data, descriptorPool, &desc_pool_state, &obj_struct);
5701c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    if (!skip) {
5702c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis        lock.unlock();
5703c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis        dev_data->dispatch_table.DestroyDescriptorPool(device, descriptorPool, pAllocator);
5704c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis        lock.lock();
5705405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (descriptorPool != VK_NULL_HANDLE) {
5706405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyDescriptorPool(dev_data, descriptorPool, desc_pool_state, obj_struct);
5707405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
5708c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    }
57095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
5710bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis// Verify cmdBuffer in given cb_node is not in global in-flight set, and return skip_call result
5711bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis//  If this is a secondary command buffer, then make sure its primary is also in-flight
5712bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis//  If primary is not in-flight, then remove secondary from global in-flight set
5713bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis// This function is only valid at a point when cmdBuffer is being reset or freed
5714cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlisstatic bool checkCommandBufferInFlight(layer_data *dev_data, const GLOBAL_CB_NODE *cb_node, const char *action,
5715cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis                                       UNIQUE_VALIDATION_ERROR_CODE error_code) {
5716bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    bool skip_call = false;
5717bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    if (dev_data->globalInFlightCmdBuffers.count(cb_node->commandBuffer)) {
5718bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        // Primary CB or secondary where primary is also in-flight is an error
5719bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        if ((cb_node->createInfo.level != VK_COMMAND_BUFFER_LEVEL_SECONDARY) ||
5720bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis            (dev_data->globalInFlightCmdBuffers.count(cb_node->primaryCommandBuffer))) {
5721cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis            skip_call |=
5722cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
5723cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis                        reinterpret_cast<const uint64_t &>(cb_node->commandBuffer), __LINE__, error_code, "DS",
5724226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "Attempt to %s command buffer (0x%p) which is in use. %s", action, cb_node->commandBuffer,
5725226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        validation_error_map[error_code]);
5726bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        }
5727bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    }
5728bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    return skip_call;
5729bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis}
5730a964cad279f9749cd9ebfc7555247ff3bff26d53Chris Forbes
5731bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis// Iterate over all cmdBuffers in given commandPool and verify that each is not in use
5732cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlisstatic bool checkCommandBuffersInFlight(layer_data *dev_data, COMMAND_POOL_NODE *pPool, const char *action,
5733cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis                                        UNIQUE_VALIDATION_ERROR_CODE error_code) {
5734bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    bool skip_call = false;
5735a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes    for (auto cmd_buffer : pPool->commandBuffers) {
5736a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes        if (dev_data->globalInFlightCmdBuffers.count(cmd_buffer)) {
57379a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            skip_call |= checkCommandBufferInFlight(dev_data, GetCBNode(dev_data, cmd_buffer), action, error_code);
5738bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        }
5739bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    }
5740bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    return skip_call;
5741bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis}
57425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5743a01b5eb150981aad061238e64b173d0da8c11140Chris Forbesstatic void clearCommandBuffersInFlight(layer_data *dev_data, COMMAND_POOL_NODE *pPool) {
5744a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes    for (auto cmd_buffer : pPool->commandBuffers) {
5745a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes        dev_data->globalInFlightCmdBuffers.erase(cmd_buffer);
5746a964cad279f9749cd9ebfc7555247ff3bff26d53Chris Forbes    }
5747a964cad279f9749cd9ebfc7555247ff3bff26d53Chris Forbes}
5748a964cad279f9749cd9ebfc7555247ff3bff26d53Chris Forbes
5749bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL FreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount,
5750bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              const VkCommandBuffer *pCommandBuffers) {
575156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
57525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool skip_call = false;
5753b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5754c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes
57555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < commandBufferCount; i++) {
57569a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto cb_node = GetCBNode(dev_data, pCommandBuffers[i]);
57575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Delete CB information structure, and remove from commandBufferMap
57589f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        if (cb_node) {
5759cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis            skip_call |= checkCommandBufferInFlight(dev_data, cb_node, "free", VALIDATION_ERROR_00096);
5760c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes        }
5761c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes    }
5762c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes
5763cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return;
5764c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes
57659a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pPool = GetCommandPoolNode(dev_data, commandPool);
5766c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes    for (uint32_t i = 0; i < commandBufferCount; i++) {
57679a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto cb_node = GetCBNode(dev_data, pCommandBuffers[i]);
5768c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes        // Delete CB information structure, and remove from commandBufferMap
57699f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        if (cb_node) {
57709f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis            dev_data->globalInFlightCmdBuffers.erase(cb_node->commandBuffer);
57715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // reset prior to delete for data clean-up
57729f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis            resetCB(dev_data, cb_node->commandBuffer);
57739f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis            dev_data->commandBufferMap.erase(cb_node->commandBuffer);
57749f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis            delete cb_node;
57755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
57765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
57775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Remove commandBuffer reference from commandPoolMap
5778c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes        pPool->commandBuffers.remove(pCommandBuffers[i]);
57795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5780b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
5781e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis
57824a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.FreeCommandBuffers(device, commandPool, commandBufferCount, pCommandBuffers);
57835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
57845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
578589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo *pCreateInfo,
5786bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkAllocationCallbacks *pAllocator, VkCommandPool *pCommandPool) {
578756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
57885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
57894a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateCommandPool(device, pCreateInfo, pAllocator, pCommandPool);
57905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
57915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
5792b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
57935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->commandPoolMap[*pCommandPool].createFlags = pCreateInfo->flags;
57945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->commandPoolMap[*pCommandPool].queueFamilyIndex = pCreateInfo->queueFamilyIndex;
57955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
57965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
57975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
57985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
579989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo *pCreateInfo,
580089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                               const VkAllocationCallbacks *pAllocator, VkQueryPool *pQueryPool) {
580156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
58020c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    bool skip = false;
58030c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    if (pCreateInfo && pCreateInfo->queryType == VK_QUERY_TYPE_PIPELINE_STATISTICS) {
58040c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis        if (!dev_data->enabled_features.pipelineStatisticsQuery) {
58050c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0,
58060c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis                            __LINE__, VALIDATION_ERROR_01006, "DS",
58070c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis                            "Query pool with type VK_QUERY_TYPE_PIPELINE_STATISTICS created on a device "
58080c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis                            "with VkDeviceCreateInfo.pEnabledFeatures.pipelineStatisticsQuery == VK_FALSE. %s",
58090c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis                            validation_error_map[VALIDATION_ERROR_01006]);
58100c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis        }
58110c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    }
58120c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis
58130c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
58140c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    if (!skip) {
58150c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis        result = dev_data->dispatch_table.CreateQueryPool(device, pCreateInfo, pAllocator, pQueryPool);
58160c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    }
58175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
5818b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
5819eafbf0b68ee6ea6e0bf33f07e0058d00a96efd9aTobin Ehlis        QUERY_POOL_NODE *qp_node = &dev_data->queryPoolMap[*pQueryPool];
5820eafbf0b68ee6ea6e0bf33f07e0058d00a96efd9aTobin Ehlis        qp_node->createInfo = *pCreateInfo;
58215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
58225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
58235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
58245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
58255f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlisstatic bool PreCallValidateDestroyCommandPool(layer_data *dev_data, VkCommandPool pool, COMMAND_POOL_NODE **cp_state) {
58269a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *cp_state = GetCommandPoolNode(dev_data, pool);
5827cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_command_pool) return false;
58285f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    bool skip = false;
58295f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    if (*cp_state) {
58305f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        // Verify that command buffers in pool are complete (not in-flight)
58315f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        skip |= checkCommandBuffersInFlight(dev_data, *cp_state, "destroy command pool with", VALIDATION_ERROR_00077);
58325f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    }
58335f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    return skip;
58345f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis}
58355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
58365f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlisstatic void PostCallRecordDestroyCommandPool(layer_data *dev_data, VkCommandPool pool, COMMAND_POOL_NODE *cp_state) {
58379f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis    // Must remove cmdpool from cmdpoolmap, after removing all cmdbuffers in its list from the commandBufferMap
58385f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    clearCommandBuffersInFlight(dev_data, cp_state);
58395f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    for (auto cb : cp_state->commandBuffers) {
5840a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes        clear_cmd_buf_and_mem_references(dev_data, cb);
58419a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto cb_node = GetCBNode(dev_data, cb);
5842d61de0e68063faa169a9a632f811c9c9adec9897Tobin Ehlis        // Remove references to this cb_node prior to delete
5843d61de0e68063faa169a9a632f811c9c9adec9897Tobin Ehlis        // TODO : Need better solution here, resetCB?
58447165385f3a39f1f951f3a6a9a06ed2cce4642b6dMark Lobodzinski        for (auto obj : cb_node->object_bindings) {
58457165385f3a39f1f951f3a6a9a06ed2cce4642b6dMark Lobodzinski            removeCommandBufferBinding(dev_data, &obj, cb_node);
58467165385f3a39f1f951f3a6a9a06ed2cce4642b6dMark Lobodzinski        }
5847d61de0e68063faa169a9a632f811c9c9adec9897Tobin Ehlis        for (auto framebuffer : cb_node->framebuffers) {
58489a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto fb_state = GetFramebufferState(dev_data, framebuffer);
5849cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (fb_state) fb_state->cb_bindings.erase(cb_node);
5850d61de0e68063faa169a9a632f811c9c9adec9897Tobin Ehlis        }
5851cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        dev_data->commandBufferMap.erase(cb);  // Remove this command buffer
5852cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        delete cb_node;                        // delete CB info structure
5853a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes    }
58545f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    dev_data->commandPoolMap.erase(pool);
58555f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis}
5856e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis
58575f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis// Destroy commandPool along with all of the commandBuffers allocated from that pool
58585f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin EhlisVKAPI_ATTR void VKAPI_CALL DestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks *pAllocator) {
585956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
58605f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    COMMAND_POOL_NODE *cp_state = nullptr;
58615f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
58625f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    bool skip = PreCallValidateDestroyCommandPool(dev_data, commandPool, &cp_state);
58635f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    if (!skip) {
58645f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        lock.unlock();
58655f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        dev_data->dispatch_table.DestroyCommandPool(device, commandPool, pAllocator);
58665f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        lock.lock();
5867405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (commandPool != VK_NULL_HANDLE) {
5868405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyCommandPool(dev_data, commandPool, cp_state);
5869405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
58705f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    }
58715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
58725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5873bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL ResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags) {
587456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
587583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
5876400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis
58771ec6311a8537f4467db08eacbd762ebaa87e70b0Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
58789a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pPool = GetCommandPoolNode(dev_data, commandPool);
5879cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis    skip_call |= checkCommandBuffersInFlight(dev_data, pPool, "reset command pool with", VALIDATION_ERROR_00072);
58801ec6311a8537f4467db08eacbd762ebaa87e70b0Chris Forbes    lock.unlock();
5881a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes
5882cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
58835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
58844a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.ResetCommandPool(device, commandPool, flags);
58855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
58865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Reset all of the CBs allocated from this pool
58875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
58881ec6311a8537f4467db08eacbd762ebaa87e70b0Chris Forbes        lock.lock();
5889a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes        clearCommandBuffersInFlight(dev_data, pPool);
5890a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes        for (auto cmdBuffer : pPool->commandBuffers) {
5891a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes            resetCB(dev_data, cmdBuffer);
58925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
58931ec6311a8537f4467db08eacbd762ebaa87e70b0Chris Forbes        lock.unlock();
58945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
58955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
58965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
58975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
589889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL ResetFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences) {
589956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
590083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
5901b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
59025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < fenceCount; ++i) {
59039a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto pFence = GetFenceNode(dev_data, pFences[i]);
5904090da73358f71ba026e2474a822fecf55267d166Chris Forbes        if (pFence && pFence->state == FENCE_INFLIGHT) {
590583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
59064527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 reinterpret_cast<const uint64_t &>(pFences[i]), __LINE__, VALIDATION_ERROR_00183, "DS",
59074527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 "Fence 0x%" PRIx64 " is in use. %s", reinterpret_cast<const uint64_t &>(pFences[i]),
59084527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 validation_error_map[VALIDATION_ERROR_00183]);
59095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
59105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5911b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
5912090da73358f71ba026e2474a822fecf55267d166Chris Forbes
5913cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
5914090da73358f71ba026e2474a822fecf55267d166Chris Forbes
59154a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.ResetFences(device, fenceCount, pFences);
5916090da73358f71ba026e2474a822fecf55267d166Chris Forbes
5917090da73358f71ba026e2474a822fecf55267d166Chris Forbes    if (result == VK_SUCCESS) {
5918090da73358f71ba026e2474a822fecf55267d166Chris Forbes        lock.lock();
5919090da73358f71ba026e2474a822fecf55267d166Chris Forbes        for (uint32_t i = 0; i < fenceCount; ++i) {
59209a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pFence = GetFenceNode(dev_data, pFences[i]);
5921090da73358f71ba026e2474a822fecf55267d166Chris Forbes            if (pFence) {
5922090da73358f71ba026e2474a822fecf55267d166Chris Forbes                pFence->state = FENCE_UNSIGNALED;
5923090da73358f71ba026e2474a822fecf55267d166Chris Forbes            }
5924090da73358f71ba026e2474a822fecf55267d166Chris Forbes        }
5925090da73358f71ba026e2474a822fecf55267d166Chris Forbes        lock.unlock();
5926090da73358f71ba026e2474a822fecf55267d166Chris Forbes    }
5927090da73358f71ba026e2474a822fecf55267d166Chris Forbes
59285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
59295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
59305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5931e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis// For given cb_nodes, invalidate them and track object causing invalidation
59320a4087f99558069e9f6a437ff2dbb5a9c1c22ccaTobin Ehlisvoid invalidateCommandBuffers(const layer_data *dev_data, std::unordered_set<GLOBAL_CB_NODE *> const &cb_nodes, VK_OBJECT obj) {
5933e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis    for (auto cb_node : cb_nodes) {
593439c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis        if (cb_node->state == CB_RECORDING) {
593539c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis            log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
5936fefa20333f94ea75877cca53d0631542cd9d0432Tobin Ehlis                    (uint64_t)(cb_node->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
5937226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    "Invalidating a command buffer that's currently being recorded: 0x%p.", cb_node->commandBuffer);
593839c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis        }
5939e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis        cb_node->state = CB_INVALID;
5940e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis        cb_node->broken_bindings.push_back(obj);
5941e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis    }
5942e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis}
5943e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis
5944c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlisstatic bool PreCallValidateDestroyFramebuffer(layer_data *dev_data, VkFramebuffer framebuffer,
5945c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis                                              FRAMEBUFFER_STATE **framebuffer_state, VK_OBJECT *obj_struct) {
59469a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *framebuffer_state = GetFramebufferState(dev_data, framebuffer);
594794165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(framebuffer), VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT};
5948cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_framebuffer) return false;
5949728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    bool skip = false;
5950728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    if (*framebuffer_state) {
5951728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *framebuffer_state, *obj_struct, VALIDATION_ERROR_00422);
5952728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    }
5953728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    return skip;
5954728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis}
5955728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis
5956c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlisstatic void PostCallRecordDestroyFramebuffer(layer_data *dev_data, VkFramebuffer framebuffer, FRAMEBUFFER_STATE *framebuffer_state,
5957728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis                                             VK_OBJECT obj_struct) {
595839c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, framebuffer_state->cb_bindings, obj_struct);
5959728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    dev_data->frameBufferMap.erase(framebuffer);
5960728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis}
5961728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis
5962bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyFramebuffer(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks *pAllocator) {
596356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5964c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    FRAMEBUFFER_STATE *framebuffer_state = nullptr;
5965728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    VK_OBJECT obj_struct;
5966b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5967728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    bool skip = PreCallValidateDestroyFramebuffer(dev_data, framebuffer, &framebuffer_state, &obj_struct);
5968728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    if (!skip) {
5969728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis        lock.unlock();
5970728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis        dev_data->dispatch_table.DestroyFramebuffer(device, framebuffer, pAllocator);
5971728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis        lock.lock();
5972405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (framebuffer != VK_NULL_HANDLE) {
5973405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyFramebuffer(dev_data, framebuffer, framebuffer_state, obj_struct);
5974405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
59755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
59765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
59775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
59780ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlisstatic bool PreCallValidateDestroyRenderPass(layer_data *dev_data, VkRenderPass render_pass, RENDER_PASS_STATE **rp_state,
59790ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis                                             VK_OBJECT *obj_struct) {
59809a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *rp_state = GetRenderPassState(dev_data, render_pass);
598194165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(render_pass), VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT};
5982cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_renderpass) return false;
59830ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    bool skip = false;
59840ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    if (*rp_state) {
59850ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *rp_state, *obj_struct, VALIDATION_ERROR_00393);
59860ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    }
59870ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    return skip;
59880ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis}
59890ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis
59900ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlisstatic void PostCallRecordDestroyRenderPass(layer_data *dev_data, VkRenderPass render_pass, RENDER_PASS_STATE *rp_state,
59910ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis                                            VK_OBJECT obj_struct) {
599239c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, rp_state->cb_bindings, obj_struct);
59930ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    dev_data->renderPassMap.erase(render_pass);
59940ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis}
59950ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis
5996bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks *pAllocator) {
599756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
59980ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    RENDER_PASS_STATE *rp_state = nullptr;
59990ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    VK_OBJECT obj_struct;
6000e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
60010ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    bool skip = PreCallValidateDestroyRenderPass(dev_data, renderPass, &rp_state, &obj_struct);
6002a9fbfe0c622e9fa4b56ddd015ed4c3c409020c2eTobin Ehlis    if (!skip) {
6003a9fbfe0c622e9fa4b56ddd015ed4c3c409020c2eTobin Ehlis        lock.unlock();
60044a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyRenderPass(device, renderPass, pAllocator);
60050ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis        lock.lock();
6006405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (renderPass != VK_NULL_HANDLE) {
6007405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyRenderPass(dev_data, renderPass, rp_state, obj_struct);
6008405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
6009a9fbfe0c622e9fa4b56ddd015ed4c3c409020c2eTobin Ehlis    }
60105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
60115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
601289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo,
601389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                            const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer) {
601456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
60153683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    std::unique_lock<std::mutex> lock(global_lock);
60163683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    bool skip = PreCallValidateCreateBuffer(dev_data, pCreateInfo);
60173683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    lock.unlock();
60183683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski
60193683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
60204a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateBuffer(device, pCreateInfo, pAllocator, pBuffer);
60215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
60225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
60233683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski        lock.lock();
60243683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski        PostCallRecordCreateBuffer(dev_data, pCreateInfo, pBuffer);
60253683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski        lock.unlock();
60265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
60275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
60285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
60295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
603089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateBufferView(VkDevice device, const VkBufferViewCreateInfo *pCreateInfo,
603189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                const VkAllocationCallbacks *pAllocator, VkBufferView *pView) {
603256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
60338c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    std::unique_lock<std::mutex> lock(global_lock);
60348c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    bool skip_call = PreCallValidateCreateBufferView(dev_data, pCreateInfo);
60358c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    lock.unlock();
6036cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
60374a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateBufferView(device, pCreateInfo, pAllocator, pView);
60385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
60398c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young        lock.lock();
60403683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski        PostCallRecordCreateBufferView(dev_data, pCreateInfo, pView);
60418c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young        lock.unlock();
60425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
60435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
60445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
60455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
60468dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski// Access helper functions for external modules
6047d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinskiconst VkFormatProperties *GetFormatProperties(core_validation::layer_data *device_data, VkFormat format) {
6048d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    VkFormatProperties *format_properties = new VkFormatProperties;
6049d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    instance_layer_data *instance_data =
6050d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski        GetLayerDataPtr(get_dispatch_key(device_data->instance_data->instance), instance_layer_data_map);
6051d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    instance_data->dispatch_table.GetPhysicalDeviceFormatProperties(device_data->physical_device, format, format_properties);
6052d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    return format_properties;
60538dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski}
60548dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski
6055d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinskiconst VkImageFormatProperties *GetImageFormatProperties(core_validation::layer_data *device_data, VkFormat format,
6056d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski                                                        VkImageType image_type, VkImageTiling tiling, VkImageUsageFlags usage,
6057d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski                                                        VkImageCreateFlags flags) {
6058d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    VkImageFormatProperties *image_format_properties = new VkImageFormatProperties;
6059d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    instance_layer_data *instance_data =
6060d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski        GetLayerDataPtr(get_dispatch_key(device_data->instance_data->instance), instance_layer_data_map);
6061d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    instance_data->dispatch_table.GetPhysicalDeviceImageFormatProperties(device_data->physical_device, format, image_type, tiling,
6062d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski                                                                         usage, flags, image_format_properties);
6063d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    return image_format_properties;
60648dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski}
60658dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski
60668dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinskiconst debug_report_data *GetReportData(core_validation::layer_data *device_data) { return device_data->report_data; }
60678dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski
60688dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinskiconst VkPhysicalDeviceProperties *GetPhysicalDeviceProperties(core_validation::layer_data *device_data) {
60698dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski    return &device_data->phys_dev_props;
60708dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski}
60718dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski
60728c59133586421be878d393799b30044497f77727Mark Lobodzinskiconst CHECK_DISABLED *GetDisables(core_validation::layer_data *device_data) { return &device_data->instance_data->disabled; }
60738c59133586421be878d393799b30044497f77727Mark Lobodzinski
60748c59133586421be878d393799b30044497f77727Mark Lobodzinskistd::unordered_map<VkImage, std::unique_ptr<IMAGE_STATE>> *GetImageMap(core_validation::layer_data *device_data) {
60758c59133586421be878d393799b30044497f77727Mark Lobodzinski    return &device_data->imageMap;
60768c59133586421be878d393799b30044497f77727Mark Lobodzinski}
60778c59133586421be878d393799b30044497f77727Mark Lobodzinski
60788c59133586421be878d393799b30044497f77727Mark Lobodzinskistd::unordered_map<VkImage, std::vector<ImageSubresourcePair>> *GetImageSubresourceMap(core_validation::layer_data *device_data) {
60798c59133586421be878d393799b30044497f77727Mark Lobodzinski    return &device_data->imageSubresourceMap;
60808c59133586421be878d393799b30044497f77727Mark Lobodzinski}
60818c59133586421be878d393799b30044497f77727Mark Lobodzinski
60828c59133586421be878d393799b30044497f77727Mark Lobodzinskistd::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> *GetImageLayoutMap(layer_data *device_data) {
60838c59133586421be878d393799b30044497f77727Mark Lobodzinski    return &device_data->imageLayoutMap;
60848c59133586421be878d393799b30044497f77727Mark Lobodzinski}
60858c59133586421be878d393799b30044497f77727Mark Lobodzinski
60863683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinskistd::unordered_map<VkBuffer, std::unique_ptr<BUFFER_STATE>> *GetBufferMap(layer_data *device_data) {
60873683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    return &device_data->bufferMap;
60883683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski}
60893683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski
60903683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinskistd::unordered_map<VkBufferView, std::unique_ptr<BUFFER_VIEW_STATE>> *GetBufferViewMap(layer_data *device_data) {
60913683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    return &device_data->bufferViewMap;
60923683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski}
60933683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski
60941c143ebdb651ea034e0b1f8731cb9f361e2f8b82Mark Lobodzinskistd::unordered_map<VkImageView, std::unique_ptr<IMAGE_VIEW_STATE>> *GetImageViewMap(layer_data *device_data) {
60951c143ebdb651ea034e0b1f8731cb9f361e2f8b82Mark Lobodzinski    return &device_data->imageViewMap;
60961c143ebdb651ea034e0b1f8731cb9f361e2f8b82Mark Lobodzinski}
60971c143ebdb651ea034e0b1f8731cb9f361e2f8b82Mark Lobodzinski
6098d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinskiconst PHYS_DEV_PROPERTIES_NODE *GetPhysDevProperties(const layer_data *device_data) {
60996a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    return &device_data->phys_dev_properties;
61006a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski}
61016a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski
610289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo,
610389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                           const VkAllocationCallbacks *pAllocator, VkImage *pImage) {
61048dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
610556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
61068dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski    bool skip = PreCallValidateCreateImage(dev_data, pCreateInfo, pAllocator, pImage);
61078dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski    if (!skip) {
61088dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski        result = dev_data->dispatch_table.CreateImage(device, pCreateInfo, pAllocator, pImage);
61098dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski    }
61105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6111b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
6112920311b6aa5614a545cad59521770d0898a75d65Mark Lobodzinski        PostCallRecordCreateImage(dev_data, pCreateInfo, pImage);
61135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
61145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
61155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
61165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
61178c07a094dc9cc4afb6b62181f341c12b9e969041Mark YoungVKAPI_ATTR VkResult VKAPI_CALL CreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo,
61188c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young                                               const VkAllocationCallbacks *pAllocator, VkImageView *pView) {
611956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
61208c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    std::unique_lock<std::mutex> lock(global_lock);
6121e3effabf8e97cae8e006477806ceaca62e4f2ce7Tobin Ehlis    bool skip = PreCallValidateCreateImageView(dev_data, pCreateInfo);
61228c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    lock.unlock();
6123cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
61244a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateImageView(device, pCreateInfo, pAllocator, pView);
61255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
61268c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young        lock.lock();
612779fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis        PostCallRecordCreateImageView(dev_data, pCreateInfo, *pView);
61288c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young        lock.unlock();
61295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6130bb6624cb996175d8945190886a200e720b3871efChris Forbes
61315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
61325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
61335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6134bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateFence(VkDevice device, const VkFenceCreateInfo *pCreateInfo,
6135bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           const VkAllocationCallbacks *pAllocator, VkFence *pFence) {
613656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
61374a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateFence(device, pCreateInfo, pAllocator, pFence);
61385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6139b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
6140a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        auto &fence_node = dev_data->fenceMap[*pFence];
61418988ad37ea5a054ff2ae3cbe4b767ae6c13cf48bChris Forbes        fence_node.fence = *pFence;
6142a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        fence_node.createInfo = *pCreateInfo;
6143cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes        fence_node.state = (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) ? FENCE_RETIRED : FENCE_UNSIGNALED;
61445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
61455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
61465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
61475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
61485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// TODO handle pipeline caches
614989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreatePipelineCache(VkDevice device, const VkPipelineCacheCreateInfo *pCreateInfo,
615089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                   const VkAllocationCallbacks *pAllocator, VkPipelineCache *pPipelineCache) {
615156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
61524a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreatePipelineCache(device, pCreateInfo, pAllocator, pPipelineCache);
61535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
61545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
61555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6156bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyPipelineCache(VkDevice device, VkPipelineCache pipelineCache,
6157bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkAllocationCallbacks *pAllocator) {
615856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
61594a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.DestroyPipelineCache(device, pipelineCache, pAllocator);
61605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
61615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6162bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL GetPipelineCacheData(VkDevice device, VkPipelineCache pipelineCache, size_t *pDataSize,
6163bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                    void *pData) {
616456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
61654a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.GetPipelineCacheData(device, pipelineCache, pDataSize, pData);
61665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
61675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
61685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6169bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL MergePipelineCaches(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount,
6170bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   const VkPipelineCache *pSrcCaches) {
617156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
61724a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.MergePipelineCaches(device, dstCache, srcCacheCount, pSrcCaches);
61735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
61745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
61755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
61763d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis// utility function to set collective state for pipeline
61774c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisvoid set_pipeline_state(PIPELINE_STATE *pPipe) {
61783d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    // If any attachment used by this pipeline has blendEnable, set top-level blendEnable
61793d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    if (pPipe->graphicsPipelineCI.pColorBlendState) {
61803d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        for (size_t i = 0; i < pPipe->attachments.size(); ++i) {
61813d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis            if (VK_TRUE == pPipe->attachments[i].blendEnable) {
61823d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                if (((pPipe->attachments[i].dstAlphaBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
61833d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                     (pPipe->attachments[i].dstAlphaBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
61843d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                    ((pPipe->attachments[i].dstColorBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
61853d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                     (pPipe->attachments[i].dstColorBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
61863d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                    ((pPipe->attachments[i].srcAlphaBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
61873d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                     (pPipe->attachments[i].srcAlphaBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
61883d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                    ((pPipe->attachments[i].srcColorBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
61893d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                     (pPipe->attachments[i].srcColorBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA))) {
61903d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                    pPipe->blendConstantsEnabled = true;
61913d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                }
61923d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis            }
61933d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        }
61943d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
61953d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis}
61963d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis
619748b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinskistatic bool PreCallCreateGraphicsPipelines(layer_data *device_data, uint32_t count,
619848b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski                                           const VkGraphicsPipelineCreateInfo *create_infos, vector<PIPELINE_STATE *> &pipe_state) {
619948b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski    bool skip = false;
6200bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    instance_layer_data *instance_data =
620156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        GetLayerDataPtr(get_dispatch_key(device_data->instance_data->instance), instance_layer_data_map);
620248b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski
620348b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski    for (uint32_t i = 0; i < count; i++) {
620448b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski        skip |= verifyPipelineCreateState(device_data, pipe_state, i);
620578b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski        if (create_infos[i].pVertexInputState != NULL) {
620678b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski            for (uint32_t j = 0; j < create_infos[i].pVertexInputState->vertexAttributeDescriptionCount; j++) {
620778b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                VkFormat format = create_infos[i].pVertexInputState->pVertexAttributeDescriptions[j].format;
620878b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                // Internal call to get format info.  Still goes through layers, could potentially go directly to ICD.
620978b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                VkFormatProperties properties;
621078b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                instance_data->dispatch_table.GetPhysicalDeviceFormatProperties(device_data->physical_device, format, &properties);
621178b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                if ((properties.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT) == 0) {
621278b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                    skip |= log_msg(
621378b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                        device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
621478b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                        __LINE__, VALIDATION_ERROR_01413, "IMAGE",
621578b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                        "vkCreateGraphicsPipelines: pCreateInfo[%d].pVertexInputState->vertexAttributeDescriptions[%d].format "
621678b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                        "(%s) is not a supported vertex buffer format. %s",
621778b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                        i, j, string_VkFormat(format), validation_error_map[VALIDATION_ERROR_01413]);
621878b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                }
621978b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski            }
622078b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski        }
622148b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski    }
622248b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski    return skip;
622348b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski}
622448b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski
6225bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
6226bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                       const VkGraphicsPipelineCreateInfo *pCreateInfos,
6227bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                       const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) {
62285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO What to do with pipelineCache?
62295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // The order of operations here is a little convoluted but gets the job done
62304c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    //  1. Pipeline create state is first shadowed into PIPELINE_STATE struct
62315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    //  2. Create state is then validated (which uses flags setup during shadowing)
62325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    //  3. If everything looks good, we'll then create the pipeline and add NODE to pipelineMap
623342486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski    bool skip = false;
62345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO : Improve this data struct w/ unique_ptrs so cleanup below is automatic
623542486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski    vector<PIPELINE_STATE *> pipe_state(count);
623656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
62375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
62385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t i = 0;
6239b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
62405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
62415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (i = 0; i < count; i++) {
624242486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski        pipe_state[i] = new PIPELINE_STATE;
624342486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski        pipe_state[i]->initGraphicsPipeline(&pCreateInfos[i]);
62449a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        pipe_state[i]->render_pass_ci.initialize(GetRenderPassState(dev_data, pCreateInfos[i].renderPass)->createInfo.ptr());
624542486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski        pipe_state[i]->pipeline_layout = *getPipelineLayout(dev_data, pCreateInfos[i].layout);
62465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
624742486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski    skip |= PreCallCreateGraphicsPipelines(dev_data, count, pCreateInfos, pipe_state);
62485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6249c70226063be6148056ceeccf835175a1fd59f24fChris Forbes    if (skip) {
6250c70226063be6148056ceeccf835175a1fd59f24fChris Forbes        for (i = 0; i < count; i++) {
6251c70226063be6148056ceeccf835175a1fd59f24fChris Forbes            delete pipe_state[i];
62521ab616b32d4e5b7d62d4a8c41b0c03ea335ab845Chris Forbes            pPipelines[i] = VK_NULL_HANDLE;
6253c70226063be6148056ceeccf835175a1fd59f24fChris Forbes        }
62547a456d188475c23b566334be45dc0489b2789653Chris Forbes        return VK_ERROR_VALIDATION_FAILED_EXT;
62557a456d188475c23b566334be45dc0489b2789653Chris Forbes    }
62567a456d188475c23b566334be45dc0489b2789653Chris Forbes
62577a456d188475c23b566334be45dc0489b2789653Chris Forbes    lock.unlock();
6258bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result =
6259bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        dev_data->dispatch_table.CreateGraphicsPipelines(device, pipelineCache, count, pCreateInfos, pAllocator, pPipelines);
62607a456d188475c23b566334be45dc0489b2789653Chris Forbes    lock.lock();
62617a456d188475c23b566334be45dc0489b2789653Chris Forbes    for (i = 0; i < count; i++) {
626261943a7503bc8594338f3364ef42f1d863486c04Chris Forbes        if (pPipelines[i] == VK_NULL_HANDLE) {
626361943a7503bc8594338f3364ef42f1d863486c04Chris Forbes            delete pipe_state[i];
6264bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        } else {
626561943a7503bc8594338f3364ef42f1d863486c04Chris Forbes            pipe_state[i]->pipeline = pPipelines[i];
626661943a7503bc8594338f3364ef42f1d863486c04Chris Forbes            dev_data->pipelineMap[pipe_state[i]->pipeline] = pipe_state[i];
626761943a7503bc8594338f3364ef42f1d863486c04Chris Forbes        }
62685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6269c70226063be6148056ceeccf835175a1fd59f24fChris Forbes
62705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
62715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
62725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6273bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
6274bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      const VkComputePipelineCreateInfo *pCreateInfos,
6275bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) {
62760108a1af0b7c6949846e9d71d00bbfb322b6f7caChris Forbes    bool skip = false;
62775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
62785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO : Improve this data struct w/ unique_ptrs so cleanup below is automatic
62794c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    vector<PIPELINE_STATE *> pPipeState(count);
628056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
62815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
62825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t i = 0;
6283b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
62845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (i = 0; i < count; i++) {
62855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // TODO: Verify compute stage bits
62865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
62875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Create and initialize internal tracking data structure
62884c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis        pPipeState[i] = new PIPELINE_STATE;
62894c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis        pPipeState[i]->initComputePipeline(&pCreateInfos[i]);
6290c2a5a36d03bbe52f5854a5884346e4a84115e259Tobin Ehlis        pPipeState[i]->pipeline_layout = *getPipelineLayout(dev_data, pCreateInfos[i].layout);
62915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
62925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // TODO: Add Compute Pipeline Verification
62930108a1af0b7c6949846e9d71d00bbfb322b6f7caChris Forbes        skip |= !validate_compute_pipeline(dev_data->report_data, pPipeState[i], &dev_data->enabled_features,
6294bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           dev_data->shaderModuleMap);
62950108a1af0b7c6949846e9d71d00bbfb322b6f7caChris Forbes        // skip |= verifyPipelineCreateState(dev_data, pPipeState[i]);
62965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
62975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
62987a456d188475c23b566334be45dc0489b2789653Chris Forbes    if (skip) {
62995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (i = 0; i < count; i++) {
63005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Clean up any locally allocated data structures
63014c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis            delete pPipeState[i];
6302fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes            pPipelines[i] = VK_NULL_HANDLE;
63035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
63045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return VK_ERROR_VALIDATION_FAILED_EXT;
63055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
63067a456d188475c23b566334be45dc0489b2789653Chris Forbes
63077a456d188475c23b566334be45dc0489b2789653Chris Forbes    lock.unlock();
6308bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result =
6309bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        dev_data->dispatch_table.CreateComputePipelines(device, pipelineCache, count, pCreateInfos, pAllocator, pPipelines);
63107a456d188475c23b566334be45dc0489b2789653Chris Forbes    lock.lock();
63117a456d188475c23b566334be45dc0489b2789653Chris Forbes    for (i = 0; i < count; i++) {
6312fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes        if (pPipelines[i] == VK_NULL_HANDLE) {
6313fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes            delete pPipeState[i];
6314bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        } else {
6315fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes            pPipeState[i]->pipeline = pPipelines[i];
6316fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes            dev_data->pipelineMap[pPipeState[i]->pipeline] = pPipeState[i];
6317fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes        }
63187a456d188475c23b566334be45dc0489b2789653Chris Forbes    }
63197a456d188475c23b566334be45dc0489b2789653Chris Forbes
63205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
63215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
63225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
632389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateSampler(VkDevice device, const VkSamplerCreateInfo *pCreateInfo,
632489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                             const VkAllocationCallbacks *pAllocator, VkSampler *pSampler) {
632556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
63264a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateSampler(device, pCreateInfo, pAllocator, pSampler);
63275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6328b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
6329d31a44af6da568692a73201825459689c9431867Tobin Ehlis        dev_data->samplerMap[*pSampler] = unique_ptr<SAMPLER_STATE>(new SAMPLER_STATE(pSampler, pCreateInfo));
63305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
63315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
63325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
63335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
63340c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlisstatic bool PreCallValidateCreateDescriptorSetLayout(layer_data *dev_data, const VkDescriptorSetLayoutCreateInfo *create_info) {
6335cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.create_descriptor_set_layout) return false;
63360c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    return cvdescriptorset::DescriptorSetLayout::ValidateCreateInfo(dev_data->report_data, create_info);
63370c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis}
63380c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis
63390c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlisstatic void PostCallRecordCreateDescriptorSetLayout(layer_data *dev_data, const VkDescriptorSetLayoutCreateInfo *create_info,
63400c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis                                                    VkDescriptorSetLayout set_layout) {
63413f1d2ba6852cf6b1bb4e1f06d690293565108e2cTobin Ehlis    // TODO: Convert this to unique_ptr to avoid leaks
63420c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    dev_data->descriptorSetLayoutMap[set_layout] = new cvdescriptorset::DescriptorSetLayout(create_info, set_layout);
63430c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis}
63440c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis
6345bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
6346bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                         const VkAllocationCallbacks *pAllocator,
6347bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                         VkDescriptorSetLayout *pSetLayout) {
634856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
63490c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
63500c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
63510c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    bool skip = PreCallValidateCreateDescriptorSetLayout(dev_data, pCreateInfo);
63520c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    if (!skip) {
63530c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis        lock.unlock();
63540c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis        result = dev_data->dispatch_table.CreateDescriptorSetLayout(device, pCreateInfo, pAllocator, pSetLayout);
63550c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis        if (VK_SUCCESS == result) {
63560c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis            lock.lock();
63570c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis            PostCallRecordCreateDescriptorSetLayout(dev_data, pCreateInfo, *pSetLayout);
63580c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis        }
63595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
63605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
63615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
63625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
63639e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz// Used by CreatePipelineLayout and CmdPushConstants.
63649e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz// Note that the index argument is optional and only used by CreatePipelineLayout.
63659e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultzstatic bool validatePushConstantRange(const layer_data *dev_data, const uint32_t offset, const uint32_t size,
63669e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz                                      const char *caller_name, uint32_t index = 0) {
6367cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.push_constant_range) return false;
63689e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    uint32_t const maxPushConstantsSize = dev_data->phys_dev_properties.properties.limits.maxPushConstantsSize;
636983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
63709e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // Check that offset + size don't exceed the max.
63719e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // Prevent arithetic overflow here by avoiding addition and testing in this order.
63729e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    if ((offset >= maxPushConstantsSize) || (size > maxPushConstantsSize - offset)) {
63739e24d8153ab63bc3ac08b5a1517c203930b5de91Karl 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.
63749e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        if (0 == strcmp(caller_name, "vkCreatePipelineLayout()")) {
6375e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis            if (offset >= maxPushConstantsSize) {
6376e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis                skip_call |=
6377e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
6378cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            VALIDATION_ERROR_00877, "DS",
6379cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s call has push constants index %u with offset %u that "
6380cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "exceeds this device's maxPushConstantSize of %u. %s",
6381e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis                            caller_name, index, offset, maxPushConstantsSize, validation_error_map[VALIDATION_ERROR_00877]);
6382e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis            }
6383e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis            if (size > maxPushConstantsSize - offset) {
6384e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis                skip_call |=
6385e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
6386cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            VALIDATION_ERROR_00880, "DS",
6387cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s call has push constants index %u with offset %u and size %u that "
6388cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "exceeds this device's maxPushConstantSize of %u. %s",
6389e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis                            caller_name, index, offset, size, maxPushConstantsSize, validation_error_map[VALIDATION_ERROR_00880]);
6390e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis            }
63919e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else if (0 == strcmp(caller_name, "vkCmdPushConstants()")) {
63924527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            if (offset >= maxPushConstantsSize) {
63934527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                skip_call |=
63944527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
6395cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            VALIDATION_ERROR_00991, "DS",
6396cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s call has push constants index %u with offset %u that "
6397cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "exceeds this device's maxPushConstantSize of %u. %s",
63984527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            caller_name, index, offset, maxPushConstantsSize, validation_error_map[VALIDATION_ERROR_00991]);
63994527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            }
64004527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            if (size > maxPushConstantsSize - offset) {
64014527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                skip_call |=
64024527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
6403cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            VALIDATION_ERROR_00992, "DS",
6404cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s call has push constants index %u with offset %u and size %u that "
6405cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "exceeds this device's maxPushConstantSize of %u. %s",
64064527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            caller_name, index, offset, size, maxPushConstantsSize, validation_error_map[VALIDATION_ERROR_00992]);
64074527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            }
64089e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else {
640983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
641083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 DRAWSTATE_INTERNAL_ERROR, "DS", "%s caller not supported.", caller_name);
64119e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
64129e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    }
64139e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // size needs to be non-zero and a multiple of 4.
64149e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    if ((size == 0) || ((size & 0x3) != 0)) {
64159e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        if (0 == strcmp(caller_name, "vkCreatePipelineLayout()")) {
6416891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis            if (size == 0) {
6417891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
6418cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     __LINE__, VALIDATION_ERROR_00878, "DS",
6419cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "%s call has push constants index %u with "
6420cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "size %u. Size must be greater than zero. %s",
6421891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis                                     caller_name, index, size, validation_error_map[VALIDATION_ERROR_00878]);
6422891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis            }
6423891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis            if (size & 0x3) {
6424891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
6425cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     __LINE__, VALIDATION_ERROR_00879, "DS",
6426cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "%s call has push constants index %u with "
6427cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "size %u. Size must be a multiple of 4. %s",
6428891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis                                     caller_name, index, size, validation_error_map[VALIDATION_ERROR_00879]);
6429891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis            }
64309e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else if (0 == strcmp(caller_name, "vkCmdPushConstants()")) {
64314527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            if (size == 0) {
64324527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
6433cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     __LINE__, VALIDATION_ERROR_01000, "DS",
6434cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "%s call has push constants index %u with "
6435cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "size %u. Size must be greater than zero. %s",
64364527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                     caller_name, index, size, validation_error_map[VALIDATION_ERROR_01000]);
64374527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            }
64384527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            if (size & 0x3) {
64394527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
6440cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     __LINE__, VALIDATION_ERROR_00990, "DS",
6441cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "%s call has push constants index %u with "
6442cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "size %u. Size must be a multiple of 4. %s",
64434527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                     caller_name, index, size, validation_error_map[VALIDATION_ERROR_00990]);
64444527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            }
64459e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else {
644683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
644783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 DRAWSTATE_INTERNAL_ERROR, "DS", "%s caller not supported.", caller_name);
64489e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
64499e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    }
64509e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // offset needs to be a multiple of 4.
64519e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    if ((offset & 0x3) != 0) {
64529e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        if (0 == strcmp(caller_name, "vkCreatePipelineLayout()")) {
645383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
6454cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 VALIDATION_ERROR_02521, "DS",
6455cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "%s call has push constants index %u with "
6456cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "offset %u. Offset must be a multiple of 4. %s",
64574527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 caller_name, index, offset, validation_error_map[VALIDATION_ERROR_02521]);
64589e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else if (0 == strcmp(caller_name, "vkCmdPushConstants()")) {
645983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
6460cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 VALIDATION_ERROR_00989, "DS",
6461cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "%s call has push constants with "
6462cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "offset %u. Offset must be a multiple of 4. %s",
64634527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 caller_name, offset, validation_error_map[VALIDATION_ERROR_00989]);
64649e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else {
646583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
646683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 DRAWSTATE_INTERNAL_ERROR, "DS", "%s caller not supported.", caller_name);
64679e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
64685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
646983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
64705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
64715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6472bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo *pCreateInfo,
647389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                    const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout) {
647483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
647556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
64761c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis    // TODO : Add checks for VALIDATION_ERRORS 865-871
64779e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // Push Constant Range checks
647807a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz    uint32_t i, j;
64795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
648083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis        skip_call |= validatePushConstantRange(dev_data, pCreateInfo->pPushConstantRanges[i].offset,
648183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                               pCreateInfo->pPushConstantRanges[i].size, "vkCreatePipelineLayout()", i);
64829e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        if (0 == pCreateInfo->pPushConstantRanges[i].stageFlags) {
648383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
64844527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 VALIDATION_ERROR_00882, "DS", "vkCreatePipelineLayout() call has no stageFlags set. %s",
64854527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 validation_error_map[VALIDATION_ERROR_00882]);
64869e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
64879e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    }
6488cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
648907a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz
64909e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // Each range has been validated.  Now check for overlap between ranges (if they are good).
649107a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz    // There's no explicit Valid Usage language against this, so issue a warning instead of an error.
649207a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz    for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
649307a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz        for (j = i + 1; j < pCreateInfo->pushConstantRangeCount; ++j) {
649407a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz            const uint32_t minA = pCreateInfo->pPushConstantRanges[i].offset;
649507a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz            const uint32_t maxA = minA + pCreateInfo->pPushConstantRanges[i].size;
649607a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz            const uint32_t minB = pCreateInfo->pPushConstantRanges[j].offset;
649707a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz            const uint32_t maxB = minB + pCreateInfo->pPushConstantRanges[j].size;
649807a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz            if ((minA <= minB && maxA > minB) || (minB <= minA && maxB > minA)) {
6499cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
6500cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     __LINE__, DRAWSTATE_PUSH_CONSTANTS_ERROR, "DS",
6501cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "vkCreatePipelineLayout() call has push constants with "
6502cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "overlapping ranges: %u:[%u, %u), %u:[%u, %u)",
6503cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     i, minA, maxA, j, minB, maxB);
65049e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz            }
65055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
65065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6507f73b2046273413ea1338dd714d67c39f8e0fa09eChris Forbes
65084a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreatePipelineLayout(device, pCreateInfo, pAllocator, pPipelineLayout);
65095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6510b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
65115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        PIPELINE_LAYOUT_NODE &plNode = dev_data->pipelineLayoutMap[*pPipelineLayout];
651269b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis        plNode.layout = *pPipelineLayout;
6513416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis        plNode.set_layouts.resize(pCreateInfo->setLayoutCount);
65145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (i = 0; i < pCreateInfo->setLayoutCount; ++i) {
65159a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            plNode.set_layouts[i] = GetDescriptorSetLayout(dev_data, pCreateInfo->pSetLayouts[i]);
65165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6517416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis        plNode.push_constant_ranges.resize(pCreateInfo->pushConstantRangeCount);
65185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
6519416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis            plNode.push_constant_ranges[i] = pCreateInfo->pPushConstantRanges[i];
65205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
65215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
65225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
65235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
65245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6525bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateDescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo *pCreateInfo,
6526bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                    const VkAllocationCallbacks *pAllocator, VkDescriptorPool *pDescriptorPool) {
652756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
65284a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateDescriptorPool(device, pCreateInfo, pAllocator, pDescriptorPool);
65295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
65305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
6531414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                    (uint64_t)*pDescriptorPool, __LINE__, DRAWSTATE_OUT_OF_MEMORY, "DS", "Created Descriptor Pool 0x%" PRIxLEAST64,
65325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    (uint64_t)*pDescriptorPool))
65335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return VK_ERROR_VALIDATION_FAILED_EXT;
6534a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis        DESCRIPTOR_POOL_STATE *pNewNode = new DESCRIPTOR_POOL_STATE(*pDescriptorPool, pCreateInfo);
65355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (NULL == pNewNode) {
65365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
65375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        (uint64_t)*pDescriptorPool, __LINE__, DRAWSTATE_OUT_OF_MEMORY, "DS",
6538a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis                        "Out of memory while attempting to allocate DESCRIPTOR_POOL_STATE in vkCreateDescriptorPool()"))
65395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return VK_ERROR_VALIDATION_FAILED_EXT;
65405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
6541b9e992386a44404152747d66817a733aa127e281Jeremy Hayes            std::lock_guard<std::mutex> lock(global_lock);
65425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->descriptorPoolMap[*pDescriptorPool] = pNewNode;
65435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
65445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
65455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Need to do anything if pool create fails?
65465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
65475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
65485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
65495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6550bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL ResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool,
6551bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   VkDescriptorPoolResetFlags flags) {
65527286e20c06011d3c6fa7edfbdbadd42bb6e8cc35Tobin Ehlis    // TODO : Add checks for VALIDATION_ERROR_00928
655356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
65544a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.ResetDescriptorPool(device, descriptorPool, flags);
65555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6556b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
65575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        clearDescriptorPool(dev_data, device, descriptorPool, flags);
65585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
65595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
65605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
65612c4e180a4442f968b44f3d5136f7ffda706f6428Chris Forbes// Ensure the pool contains enough descriptors and descriptor sets to satisfy
6562789832b514862c7a7b5b847eeb8e7cacb733b77bTobin Ehlis// an allocation request. Fills common_data with the total number of descriptors of each type required,
6563789832b514862c7a7b5b847eeb8e7cacb733b77bTobin Ehlis// as well as DescriptorSetLayout ptrs used for later update.
65647f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlisstatic bool PreCallValidateAllocateDescriptorSets(layer_data *dev_data, const VkDescriptorSetAllocateInfo *pAllocateInfo,
65657f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis                                                  cvdescriptorset::AllocateDescriptorSetsData *common_data) {
6566cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.allocate_descriptor_sets) return false;
65677e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlis    // All state checks for AllocateDescriptorSets is done in single function
6568e3f7c45fd64a44a67ce96c89e2bbee426c6ecf24Tobin Ehlis    return cvdescriptorset::ValidateAllocateDescriptorSets(dev_data->report_data, pAllocateInfo, dev_data, common_data);
65697e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlis}
65707e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlis// Allocation state was good and call down chain was made so update state based on allocating descriptor sets
65717e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlisstatic void PostCallRecordAllocateDescriptorSets(layer_data *dev_data, const VkDescriptorSetAllocateInfo *pAllocateInfo,
65727f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis                                                 VkDescriptorSet *pDescriptorSets,
65737f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis                                                 const cvdescriptorset::AllocateDescriptorSetsData *common_data) {
65747e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlis    // All the updates are contained in a single cvdescriptorset function
65752c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    cvdescriptorset::PerformAllocateDescriptorSets(pAllocateInfo, pDescriptorSets, common_data, &dev_data->descriptorPoolMap,
6576b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis                                                   &dev_data->setMap, dev_data);
65772c4e180a4442f968b44f3d5136f7ffda706f6428Chris Forbes}
65782c4e180a4442f968b44f3d5136f7ffda706f6428Chris Forbes
6579bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL AllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo,
6580bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      VkDescriptorSet *pDescriptorSets) {
658156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
6582b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
65837f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis    cvdescriptorset::AllocateDescriptorSetsData common_data(pAllocateInfo->descriptorSetCount);
65847f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis    bool skip_call = PreCallValidateAllocateDescriptorSets(dev_data, pAllocateInfo, &common_data);
6585b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
6586d173e0daab123373ce75105f2a908f6ae7cef6abChris Forbes
6587cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
6588d173e0daab123373ce75105f2a908f6ae7cef6abChris Forbes
65894a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.AllocateDescriptorSets(device, pAllocateInfo, pDescriptorSets);
65906511ce241f7f210211e0c0e882f3c14889071f4dChris Forbes
65915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6592b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
65937f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis        PostCallRecordAllocateDescriptorSets(dev_data, pAllocateInfo, pDescriptorSets, &common_data);
6594b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
65955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
65965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
65975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
6598cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis// Verify state before freeing DescriptorSets
6599cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlisstatic bool PreCallValidateFreeDescriptorSets(const layer_data *dev_data, VkDescriptorPool pool, uint32_t count,
6600cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis                                              const VkDescriptorSet *descriptor_sets) {
6601cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.free_descriptor_sets) return false;
6602cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    bool skip_call = false;
6603cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    // First make sure sets being destroyed are not currently in-use
6604405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour    for (uint32_t i = 0; i < count; ++i) {
6605405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (descriptor_sets[i] != VK_NULL_HANDLE) {
6606405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            skip_call |= validateIdleDescriptorSet(dev_data, descriptor_sets[i], "vkFreeDescriptorSets");
6607405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
6608405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour    }
6609cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis
66109a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DESCRIPTOR_POOL_STATE *pool_state = GetDescriptorPoolState(dev_data, pool);
6611a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis    if (pool_state && !(VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT & pool_state->createInfo.flags)) {
6612cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis        // Can't Free from a NON_FREE pool
6613cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
66141c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis                             reinterpret_cast<uint64_t &>(pool), __LINE__, VALIDATION_ERROR_00922, "DS",
6615cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis                             "It is invalid to call vkFreeDescriptorSets() with a pool created without setting "
66161c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis                             "VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT. %s",
66171c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis                             validation_error_map[VALIDATION_ERROR_00922]);
6618cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    }
6619cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    return skip_call;
6620cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis}
6621cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis// Sets have been removed from the pool so update underlying state
6622cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlisstatic void PostCallRecordFreeDescriptorSets(layer_data *dev_data, VkDescriptorPool pool, uint32_t count,
6623cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis                                             const VkDescriptorSet *descriptor_sets) {
66249a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DESCRIPTOR_POOL_STATE *pool_state = GetDescriptorPoolState(dev_data, pool);
6625cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    // Update available descriptor sets in pool
6626cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    pool_state->availableSets += count;
6627cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis
6628cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    // For each freed descriptor add its resources back into the pool as available and remove from pool and setMap
6629cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    for (uint32_t i = 0; i < count; ++i) {
6630405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (descriptor_sets[i] != VK_NULL_HANDLE) {
6631405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            auto descriptor_set = dev_data->setMap[descriptor_sets[i]];
6632405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            uint32_t type_index = 0, descriptor_count = 0;
6633405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            for (uint32_t j = 0; j < descriptor_set->GetBindingCount(); ++j) {
6634405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour                type_index = static_cast<uint32_t>(descriptor_set->GetTypeFromIndex(j));
6635405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour                descriptor_count = descriptor_set->GetDescriptorCountFromIndex(j);
6636405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour                pool_state->availableDescriptorTypeCount[type_index] += descriptor_count;
6637405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            }
6638405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            freeDescriptorSet(dev_data, descriptor_set);
6639405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            pool_state->sets.erase(descriptor_set);
6640405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
6641cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    }
6642cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis}
66435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6644bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL FreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t count,
6645bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                  const VkDescriptorSet *pDescriptorSets) {
664656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
66475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Make sure that no sets being destroyed are in-flight
6648b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
664983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = PreCallValidateFreeDescriptorSets(dev_data, descriptorPool, count, pDescriptorSets);
6650b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
6651e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis
6652cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
66534a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.FreeDescriptorSets(device, descriptorPool, count, pDescriptorSets);
66545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6655b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
6656cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis        PostCallRecordFreeDescriptorSets(dev_data, descriptorPool, count, pDescriptorSets);
6657b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
66585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
66595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
66605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
66616b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis// TODO : This is a Proof-of-concept for core validation architecture
66626b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis//  Really we'll want to break out these functions to separate files but
66636b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis//  keeping it all together here to prove out design
66646b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis// PreCallValidate* handles validating all of the state prior to calling down chain to UpdateDescriptorSets()
66656b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlisstatic bool PreCallValidateUpdateDescriptorSets(layer_data *dev_data, uint32_t descriptorWriteCount,
66666b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                                const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
66676b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                                const VkCopyDescriptorSet *pDescriptorCopies) {
6668cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.update_descriptor_sets) return false;
66696b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // First thing to do is perform map look-ups.
66706b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // NOTE : UpdateDescriptorSets is somewhat unique in that it's operating on a number of DescriptorSets
66716b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    //  so we can't just do a single map look-up up-front, but do them individually in functions below
66726b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis
66736b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // Now make call(s) that validate state, but don't perform state updates in this function
66746b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // Note, here DescriptorSets is unique in that we don't yet have an instance. Using a helper function in the
66756b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    //  namespace which will parse params and make calls into specific class instances
6676104ab082916e41467ef60baaab7a5a8b2e02c59cTobin Ehlis    return cvdescriptorset::ValidateUpdateDescriptorSets(dev_data->report_data, dev_data, descriptorWriteCount, pDescriptorWrites,
6677104ab082916e41467ef60baaab7a5a8b2e02c59cTobin Ehlis                                                         descriptorCopyCount, pDescriptorCopies);
66786b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis}
66796b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis// PostCallRecord* handles recording state updates following call down chain to UpdateDescriptorSets()
66806b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlisstatic void PostCallRecordUpdateDescriptorSets(layer_data *dev_data, uint32_t descriptorWriteCount,
66816b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                               const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
66826b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                               const VkCopyDescriptorSet *pDescriptorCopies) {
6683104ab082916e41467ef60baaab7a5a8b2e02c59cTobin Ehlis    cvdescriptorset::PerformUpdateDescriptorSets(dev_data, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
66846b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                                 pDescriptorCopies);
66856b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis}
66865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6687bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL UpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount,
6688bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
6689bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkCopyDescriptorSet *pDescriptorCopies) {
66906b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // Only map look-up at top level is for device-level layer_data
669156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
6692b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
66936b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    bool skip_call = PreCallValidateUpdateDescriptorSets(dev_data, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
66946b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                                         pDescriptorCopies);
6695b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
66966b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    if (!skip_call) {
66974a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.UpdateDescriptorSets(device, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
66984a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                      pDescriptorCopies);
66996b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis        lock.lock();
67006b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis        // Since UpdateDescriptorSets() is void, nothing to check prior to updating state
67016b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis        PostCallRecordUpdateDescriptorSets(dev_data, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
67026b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                           pDescriptorCopies);
67035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
67045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
67055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6706bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL AllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pCreateInfo,
6707bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      VkCommandBuffer *pCommandBuffer) {
670856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
67094a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.AllocateCommandBuffers(device, pCreateInfo, pCommandBuffer);
67105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6711b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::unique_lock<std::mutex> lock(global_lock);
67129a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto pPool = GetCommandPoolNode(dev_data, pCreateInfo->commandPool);
6713cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes
6714cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes        if (pPool) {
671572d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis            for (uint32_t i = 0; i < pCreateInfo->commandBufferCount; i++) {
67165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // Add command buffer to its commandPool map
6717cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes                pPool->commandBuffers.push_back(pCommandBuffer[i]);
67185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                GLOBAL_CB_NODE *pCB = new GLOBAL_CB_NODE;
67195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // Add command buffer to map
67205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                dev_data->commandBufferMap[pCommandBuffer[i]] = pCB;
67215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                resetCB(dev_data, pCommandBuffer[i]);
67225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pCB->createInfo = *pCreateInfo;
67235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pCB->device = device;
67245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
67255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6726b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
67275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
67285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
67295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
67305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6731883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis// Add bindings between the given cmd buffer & framebuffer and the framebuffer's children
6732c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlisstatic void AddFramebufferBinding(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, FRAMEBUFFER_STATE *fb_state) {
67330245b74a083d2cb3b083571deb0fe13b4ab428a4Tobin Ehlis    addCommandBufferBinding(&fb_state->cb_bindings,
67340245b74a083d2cb3b083571deb0fe13b4ab428a4Tobin Ehlis                            {reinterpret_cast<uint64_t &>(fb_state->framebuffer), VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT},
67350245b74a083d2cb3b083571deb0fe13b4ab428a4Tobin Ehlis                            cb_state);
6736883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis    for (auto attachment : fb_state->attachments) {
6737883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        auto view_state = attachment.view_state;
6738883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        if (view_state) {
673903ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis            AddCommandBufferBindingImageView(dev_data, cb_state, view_state);
6740883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        }
67419a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto rp_state = GetRenderPassState(dev_data, fb_state->createInfo.renderPass);
6742883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        if (rp_state) {
6743883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis            addCommandBufferBinding(
6744883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis                &rp_state->cb_bindings,
6745883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis                {reinterpret_cast<uint64_t &>(rp_state->renderPass), VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT}, cb_state);
6746883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        }
6747883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis    }
6748883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis}
6749883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis
6750bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL BeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo) {
675183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
675256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6753b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
67545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Validate command buffer level
67559a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *cb_node = GetCBNode(dev_data, commandBuffer);
6756f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis    if (cb_node) {
67575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // This implicitly resets the Cmd Buffer so make sure any fence is done and then clear memory references
6758a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        if (dev_data->globalInFlightCmdBuffers.count(commandBuffer)) {
675983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |=
6760a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
67614527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                        (uint64_t)commandBuffer, __LINE__, VALIDATION_ERROR_00104, "MEM",
6762d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen                        "Calling vkBeginCommandBuffer() on active command buffer 0x%p before it has completed. "
67634527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                        "You must check command buffer fence before this call. %s",
67644527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                        commandBuffer, validation_error_map[VALIDATION_ERROR_00104]);
67655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6766f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        clear_cmd_buf_and_mem_references(dev_data, cb_node);
6767f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        if (cb_node->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
67685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Secondary Command Buffer
67695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            const VkCommandBufferInheritanceInfo *pInfo = pBeginInfo->pInheritanceInfo;
67705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!pInfo) {
677183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                skip_call |=
67725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
67734527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            reinterpret_cast<uint64_t>(commandBuffer), __LINE__, VALIDATION_ERROR_00106, "DS",
6774bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "vkBeginCommandBuffer(): Secondary Command Buffer (0x%p) must have inheritance info. %s", commandBuffer,
6775bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            validation_error_map[VALIDATION_ERROR_00106]);
67765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else {
67775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (pBeginInfo->flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT) {
67782c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                    // Object_tracker makes sure these objects are valid
67792c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                    assert(pInfo->renderPass);
67802c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                    assert(pInfo->framebuffer);
67812c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                    string errorString = "";
67829a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto framebuffer = GetFramebufferState(dev_data, pInfo->framebuffer);
67832c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                    if (framebuffer) {
67842c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                        if ((framebuffer->createInfo.renderPass != pInfo->renderPass) &&
67852c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                            !verify_renderpass_compatibility(dev_data, framebuffer->renderPassCreateInfo.ptr(),
67869a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                                                             GetRenderPassState(dev_data, pInfo->renderPass)->createInfo.ptr(),
67872c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                             errorString)) {
67882c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                            // renderPass that framebuffer was created with must be compatible with local renderPass
67892c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
67902c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
67912c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                 reinterpret_cast<uint64_t>(commandBuffer), __LINE__, VALIDATION_ERROR_00112, "DS",
67922c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                 "vkBeginCommandBuffer(): Secondary Command "
6793cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                 "Buffer (0x%p) renderPass (0x%" PRIxLEAST64
6794cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                 ") is incompatible w/ framebuffer "
67952c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                 "(0x%" PRIxLEAST64 ") w/ render pass (0x%" PRIxLEAST64 ") due to: %s. %s",
67962c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                 commandBuffer, reinterpret_cast<const uint64_t &>(pInfo->renderPass),
67972c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                 reinterpret_cast<const uint64_t &>(pInfo->framebuffer),
67982c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                 reinterpret_cast<uint64_t &>(framebuffer->createInfo.renderPass),
67992c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                 errorString.c_str(), validation_error_map[VALIDATION_ERROR_00112]);
68005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        }
68012c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                        // Connect this framebuffer and its children to this cmdBuffer
68022c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                        AddFramebufferBinding(dev_data, cb_node, framebuffer);
68035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
68045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
68054527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                if ((pInfo->occlusionQueryEnable == VK_FALSE || dev_data->enabled_features.occlusionQueryPrecise == VK_FALSE) &&
68065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    (pInfo->queryFlags & VK_QUERY_CONTROL_PRECISE_BIT)) {
680783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
680883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                         VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t>(commandBuffer),
68094527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                         __LINE__, VALIDATION_ERROR_00107, "DS",
681083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                         "vkBeginCommandBuffer(): Secondary Command Buffer (0x%p) must not have "
681183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                         "VK_QUERY_CONTROL_PRECISE_BIT if occulusionQuery is disabled or the device does not "
68124527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                         "support precise occlusion queries. %s",
68134527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                         commandBuffer, validation_error_map[VALIDATION_ERROR_00107]);
68145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
68155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
68165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (pInfo && pInfo->renderPass != VK_NULL_HANDLE) {
68179a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto renderPass = GetRenderPassState(dev_data, pInfo->renderPass);
681816387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                if (renderPass) {
6819fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes                    if (pInfo->subpass >= renderPass->createInfo.subpassCount) {
682083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                        skip_call |= log_msg(
6821bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6822bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            (uint64_t)commandBuffer, __LINE__, VALIDATION_ERROR_00111, "DS",
68234527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            "vkBeginCommandBuffer(): Secondary Command Buffers (0x%p) must have a subpass index (%d) "
68244527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            "that is less than the number of subpasses (%d). %s",
68254527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            commandBuffer, pInfo->subpass, renderPass->createInfo.subpassCount,
68264527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            validation_error_map[VALIDATION_ERROR_00111]);
68275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
68285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
68295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
68305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6831f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        if (CB_RECORDING == cb_node->state) {
6832cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            skip_call |=
6833cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6834cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        (uint64_t)commandBuffer, __LINE__, VALIDATION_ERROR_00103, "DS",
6835cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "vkBeginCommandBuffer(): Cannot call Begin on command buffer (0x%p"
6836cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        ") in the RECORDING state. Must first call vkEndCommandBuffer(). %s",
6837cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        commandBuffer, validation_error_map[VALIDATION_ERROR_00103]);
6838347d4d3139a1e743ed85bd375c20fd35bbe68d74Chris Forbes        } else if (CB_RECORDED == cb_node->state || (CB_INVALID == cb_node->state && CMD_END == cb_node->last_cmd)) {
6839f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            VkCommandPool cmdPool = cb_node->createInfo.commandPool;
68409a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pPool = GetCommandPoolNode(dev_data, cmdPool);
6841cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes            if (!(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT & pPool->createFlags)) {
684283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                skip_call |=
68435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
68444527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            (uint64_t)commandBuffer, __LINE__, VALIDATION_ERROR_00105, "DS",
6845226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                            "Call to vkBeginCommandBuffer() on command buffer (0x%p"
6846414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                            ") attempts to implicitly reset cmdBuffer created from command pool (0x%" PRIxLEAST64
68474527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            ") that does NOT have the VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT bit set. %s",
68484527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            commandBuffer, (uint64_t)cmdPool, validation_error_map[VALIDATION_ERROR_00105]);
68495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
68505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            resetCB(dev_data, commandBuffer);
68515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
68525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Set updated state here in case implicit reset occurs above
6853f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        cb_node->state = CB_RECORDING;
6854f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        cb_node->beginInfo = *pBeginInfo;
6855f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        if (cb_node->beginInfo.pInheritanceInfo) {
6856f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->inheritanceInfo = *(cb_node->beginInfo.pInheritanceInfo);
6857f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->beginInfo.pInheritanceInfo = &cb_node->inheritanceInfo;
6858888e1d268098177fde4a2263e3d7b7cc415f1debMark Young            // If we are a secondary command-buffer and inheriting.  Update the items we should inherit.
6859f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            if ((cb_node->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) &&
6860f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                (cb_node->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
68619a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                cb_node->activeRenderPass = GetRenderPassState(dev_data, cb_node->beginInfo.pInheritanceInfo->renderPass);
6862f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                cb_node->activeSubpass = cb_node->beginInfo.pInheritanceInfo->subpass;
6863350841afb70bf8dcfc3c6ec6b66f0aaa639553a3Tobin Ehlis                cb_node->activeFramebuffer = cb_node->beginInfo.pInheritanceInfo->framebuffer;
6864f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                cb_node->framebuffers.insert(cb_node->beginInfo.pInheritanceInfo->framebuffer);
6865888e1d268098177fde4a2263e3d7b7cc415f1debMark Young            }
68665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
68675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6868b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
686983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (skip_call) {
68705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return VK_ERROR_VALIDATION_FAILED_EXT;
68715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
68724a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.BeginCommandBuffer(commandBuffer, pBeginInfo);
6873400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis
68745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
68755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
68765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
687789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL EndCommandBuffer(VkCommandBuffer commandBuffer) {
687883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
68795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_SUCCESS;
688056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6881b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
68829a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
68835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
68844527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton        if ((VK_COMMAND_BUFFER_LEVEL_PRIMARY == pCB->createInfo.level) ||
68854527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
6886fd61966f8d41b5bce15620b70563b7864cbb28feCody Northrop            // This needs spec clarification to update valid usage, see comments in PR:
6887fd61966f8d41b5bce15620b70563b7864cbb28feCody Northrop            // https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/pull/516#discussion_r63013756
6888ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen            skip_call |= insideRenderPass(dev_data, pCB, "vkEndCommandBuffer()", VALIDATION_ERROR_00123);
6889fd61966f8d41b5bce15620b70563b7864cbb28feCody Northrop        }
689029f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_END, "vkEndCommandBuffer()");
68911ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_END);
68925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto query : pCB->activeQueries) {
689383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
68944527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 VALIDATION_ERROR_00124, "DS",
68954527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 "Ending command buffer with in progress query: queryPool 0x%" PRIx64 ", index %d. %s",
68964527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 (uint64_t)(query.pool), query.index, validation_error_map[VALIDATION_ERROR_00124]);
68975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
68985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
689983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (!skip_call) {
6900b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
69014a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.EndCommandBuffer(commandBuffer);
6902b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
69035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (VK_SUCCESS == result) {
69045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pCB->state = CB_RECORDED;
69055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Reset CB status flags
69065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pCB->status = 0;
69075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
69085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
69095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        result = VK_ERROR_VALIDATION_FAILED_EXT;
69105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6911b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
69125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
69135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
69145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6915bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL ResetCommandBuffer(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags) {
6916bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    bool skip_call = false;
691756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6918b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
69199a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
69205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkCommandPool cmdPool = pCB->createInfo.commandPool;
69219a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pPool = GetCommandPoolNode(dev_data, cmdPool);
6922cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes    if (!(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT & pPool->createFlags)) {
6923bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
69244527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                             (uint64_t)commandBuffer, __LINE__, VALIDATION_ERROR_00093, "DS",
6925226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                             "Attempt to reset command buffer (0x%p) created from command pool (0x%" PRIxLEAST64
69264527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                             ") that does NOT have the VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT bit set. %s",
69274527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                             commandBuffer, (uint64_t)cmdPool, validation_error_map[VALIDATION_ERROR_00093]);
69285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6929cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis    skip_call |= checkCommandBufferInFlight(dev_data, pCB, "reset", VALIDATION_ERROR_00092);
6930b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
6931cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
69324a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.ResetCommandBuffer(commandBuffer, flags);
69335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6934b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
6935a964cad279f9749cd9ebfc7555247ff3bff26d53Chris Forbes        dev_data->globalInFlightCmdBuffers.erase(commandBuffer);
69365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        resetCB(dev_data, commandBuffer);
6937b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
69385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
69395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
69405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
694193c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski
6942bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBindPipeline(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
6943bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           VkPipeline pipeline) {
6944e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis    bool skip = false;
694556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6946b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
69479a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
6948e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis    if (cb_state) {
694929f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip |= ValidateCmd(dev_data, cb_state, CMD_BINDPIPELINE, "vkCmdBindPipeline()");
69501ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(cb_state, CMD_BINDPIPELINE);
6951e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        if ((VK_PIPELINE_BIND_POINT_COMPUTE == pipelineBindPoint) && (cb_state->activeRenderPass)) {
6952e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            skip |=
69535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
69545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        (uint64_t)pipeline, __LINE__, DRAWSTATE_INVALID_RENDERPASS_CMD, "DS",
6955414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                        "Incorrectly binding compute pipeline (0x%" PRIxLEAST64 ") during active RenderPass (0x%" PRIxLEAST64 ")",
6956e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis                        (uint64_t)pipeline, (uint64_t)cb_state->activeRenderPass->renderPass);
69575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
69584527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton        // TODO: VALIDATION_ERROR_00594 VALIDATION_ERROR_00596
69595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6960e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        PIPELINE_STATE *pipe_state = getPipelineState(dev_data, pipeline);
6961e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        if (pipe_state) {
6962e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            cb_state->lastBound[pipelineBindPoint].pipeline_state = pipe_state;
6963e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            set_cb_pso_status(cb_state, pipe_state);
6964e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            set_pipeline_state(pipe_state);
69655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
6966e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
69674527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            (uint64_t)pipeline, __LINE__, VALIDATION_ERROR_00600, "DS",
69684527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            "Attempt to bind Pipeline 0x%" PRIxLEAST64 " that doesn't exist! %s", (uint64_t)(pipeline),
69694527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            validation_error_map[VALIDATION_ERROR_00600]);
6970e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        }
6971e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        addCommandBufferBinding(&pipe_state->cb_bindings,
6972e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis                                {reinterpret_cast<uint64_t &>(pipeline), VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT}, cb_state);
6973e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        if (VK_PIPELINE_BIND_POINT_GRAPHICS == pipelineBindPoint) {
6974e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            // Add binding for child renderpass
69759a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto rp_state = GetRenderPassState(dev_data, pipe_state->graphicsPipelineCI.renderPass);
6976e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            if (rp_state) {
6977e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis                addCommandBufferBinding(
6978e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis                    &rp_state->cb_bindings,
6979e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis                    {reinterpret_cast<uint64_t &>(rp_state->renderPass), VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT}, cb_state);
6980e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            }
69815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
69825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6983b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
6984cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdBindPipeline(commandBuffer, pipelineBindPoint, pipeline);
69855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
69865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6987bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetViewport(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount,
6988bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                          const VkViewport *pViewports) {
698983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
699056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6991b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
69929a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
69935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
699429f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETVIEWPORTSTATE, "vkCmdSetViewport()");
69951ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETVIEWPORTSTATE);
6996bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pCB->viewportMask |= ((1u << viewportCount) - 1u) << firstViewport;
69975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6998b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
6999cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetViewport(commandBuffer, firstViewport, viewportCount, pViewports);
70005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
70015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7002bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetScissor(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount,
7003bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         const VkRect2D *pScissors) {
700483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
700556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7006b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
70079a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
70085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
700929f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETSCISSORSTATE, "vkCmdSetScissor()");
70101ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETSCISSORSTATE);
7011bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pCB->scissorMask |= ((1u << scissorCount) - 1u) << firstScissor;
70125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7013b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7014cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetScissor(commandBuffer, firstScissor, scissorCount, pScissors);
70155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
70165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
701789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth) {
7018a27508babf63d50aea75883a3702979193c23683Mark Young    bool skip_call = false;
701956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7020b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
70219a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
70225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
702329f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETLINEWIDTHSTATE, "vkCmdSetLineWidth()");
70241ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETLINEWIDTHSTATE);
70255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_LINE_WIDTH_SET;
7026a27508babf63d50aea75883a3702979193c23683Mark Young
70274c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis        PIPELINE_STATE *pPipeTrav = pCB->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].pipeline_state;
7028a27508babf63d50aea75883a3702979193c23683Mark Young        if (pPipeTrav != NULL && !isDynamic(pPipeTrav, VK_DYNAMIC_STATE_LINE_WIDTH)) {
7029a27508babf63d50aea75883a3702979193c23683Mark Young            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0,
703055eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                 reinterpret_cast<uint64_t &>(commandBuffer), __LINE__, VALIDATION_ERROR_01476, "DS",
7031386d9a9a77f884789a7ae4c3890aecd47132f2babaldurk                                 "vkCmdSetLineWidth called but pipeline was created without VK_DYNAMIC_STATE_LINE_WIDTH "
703255eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                 "flag.  This is undefined behavior and could be ignored. %s",
703355eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                 validation_error_map[VALIDATION_ERROR_01476]);
7034a27508babf63d50aea75883a3702979193c23683Mark Young        } else {
7035a27508babf63d50aea75883a3702979193c23683Mark Young            skip_call |= verifyLineWidth(dev_data, DRAWSTATE_INVALID_SET, reinterpret_cast<uint64_t &>(commandBuffer), lineWidth);
7036a27508babf63d50aea75883a3702979193c23683Mark Young        }
70375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7038b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7039cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetLineWidth(commandBuffer, lineWidth);
70405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
70415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7042bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetDepthBias(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp,
7043bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           float depthBiasSlopeFactor) {
704483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
704556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7046b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
70479a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
70485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
704929f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETDEPTHBIASSTATE, "vkCmdSetDepthBias()");
70501ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETDEPTHBIASSTATE);
70515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_DEPTH_BIAS_SET;
70525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7053b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
705483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (!skip_call)
70554a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdSetDepthBias(commandBuffer, depthBiasConstantFactor, depthBiasClamp, depthBiasSlopeFactor);
70565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
70575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
705889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdSetBlendConstants(VkCommandBuffer commandBuffer, const float blendConstants[4]) {
705983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
706056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7061b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
70629a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
70635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
706429f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETBLENDSTATE, "vkCmdSetBlendConstants()");
70651ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETBLENDSTATE);
70663d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        pCB->status |= CBSTATUS_BLEND_CONSTANTS_SET;
70675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7068b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7069cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetBlendConstants(commandBuffer, blendConstants);
70705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
70715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7072bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetDepthBounds(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds) {
707383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
707456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7075b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
70769a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
70775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
707829f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETDEPTHBOUNDSSTATE, "vkCmdSetDepthBounds()");
70791ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETDEPTHBOUNDSSTATE);
70805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_DEPTH_BOUNDS_SET;
70815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7082b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7083cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetDepthBounds(commandBuffer, minDepthBounds, maxDepthBounds);
70845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
70855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7086bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetStencilCompareMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask,
7087bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                    uint32_t compareMask) {
708883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
708956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7090b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
70919a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
70925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
709329f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETSTENCILREADMASKSTATE, "vkCmdSetStencilCompareMask()");
70941ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETSTENCILREADMASKSTATE);
70955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_STENCIL_READ_MASK_SET;
70965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7097b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7098cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetStencilCompareMask(commandBuffer, faceMask, compareMask);
70995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
71005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7101bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetStencilWriteMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask) {
710283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
710356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7104b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
71059a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
71065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
710729f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETSTENCILWRITEMASKSTATE, "vkCmdSetStencilWriteMask()");
71081ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETSTENCILWRITEMASKSTATE);
71095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_STENCIL_WRITE_MASK_SET;
71105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7111b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7112cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetStencilWriteMask(commandBuffer, faceMask, writeMask);
71135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
71145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7115bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetStencilReference(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference) {
711683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
711756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7118b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
71199a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
71205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
712129f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETSTENCILREFERENCESTATE, "vkCmdSetStencilReference()");
71221ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETSTENCILREFERENCESTATE);
71235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_STENCIL_REFERENCE_SET;
71245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7125b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7126cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetStencilReference(commandBuffer, faceMask, reference);
71275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
71285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7129bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBindDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
7130bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 VkPipelineLayout layout, uint32_t firstSet, uint32_t setCount,
7131bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkDescriptorSet *pDescriptorSets, uint32_t dynamicOffsetCount,
7132bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const uint32_t *pDynamicOffsets) {
713383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
713456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7135b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
71369a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
71375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
71385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (pCB->state == CB_RECORDING) {
7139787f29d93dee194c015789cf61c079504c980572Tobin Ehlis            // Track total count of dynamic descriptor types to make sure we have an offset for each one
7140787f29d93dee194c015789cf61c079504c980572Tobin Ehlis            uint32_t totalDynamicDescriptors = 0;
7141787f29d93dee194c015789cf61c079504c980572Tobin Ehlis            string errorString = "";
7142787f29d93dee194c015789cf61c079504c980572Tobin Ehlis            uint32_t lastSetIndex = firstSet + setCount - 1;
7143dd725b03ae4d1296a722d0ec5c9fe63941cabe4bChris Forbes            if (lastSetIndex >= pCB->lastBound[pipelineBindPoint].boundDescriptorSets.size()) {
714472d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                pCB->lastBound[pipelineBindPoint].boundDescriptorSets.resize(lastSetIndex + 1);
7145dd725b03ae4d1296a722d0ec5c9fe63941cabe4bChris Forbes                pCB->lastBound[pipelineBindPoint].dynamicOffsets.resize(lastSetIndex + 1);
7146dd725b03ae4d1296a722d0ec5c9fe63941cabe4bChris Forbes            }
714771511c5a10533c910bfe62c3bcf58e2a4054e7acTobin Ehlis            auto oldFinalBoundSet = pCB->lastBound[pipelineBindPoint].boundDescriptorSets[lastSetIndex];
7148c2a5a36d03bbe52f5854a5884346e4a84115e259Tobin Ehlis            auto pipeline_layout = getPipelineLayout(dev_data, layout);
71499784e78683f658f304062235ceb2dd2c2652c357Karl Schultz            for (uint32_t set_idx = 0; set_idx < setCount; set_idx++) {
71509a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                cvdescriptorset::DescriptorSet *descriptor_set = GetSetNode(dev_data, pDescriptorSets[set_idx]);
71511c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                if (descriptor_set) {
715269b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                    pCB->lastBound[pipelineBindPoint].pipeline_layout = *pipeline_layout;
71539784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                    pCB->lastBound[pipelineBindPoint].boundDescriptorSets[set_idx + firstSet] = descriptor_set;
715483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT,
71559784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                                         VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[set_idx],
71569784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                                         __LINE__, DRAWSTATE_NONE, "DS", "Descriptor Set 0x%" PRIxLEAST64 " bound on pipeline %s",
71579784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                                         (uint64_t)pDescriptorSets[set_idx], string_VkPipelineBindPoint(pipelineBindPoint));
71581c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                    if (!descriptor_set->IsUpdated() && (descriptor_set->GetTotalDescriptorCount() != 0)) {
715983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
71609784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                                             VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[set_idx],
71619784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                                             __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS",
7162d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen                                             "Descriptor Set 0x%" PRIxLEAST64
716383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                             " bound but it was never updated. You may want to either update it or not bind it.",
71649784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                                             (uint64_t)pDescriptorSets[set_idx]);
7165787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                    }
7166787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                    // Verify that set being bound is compatible with overlapping setLayout of pipelineLayout
71679784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                    if (!verify_set_layout_compatibility(dev_data, descriptor_set, pipeline_layout, set_idx + firstSet,
71689784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                                                         errorString)) {
716983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
71709784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                                             VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[set_idx],
71719784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                                             __LINE__, VALIDATION_ERROR_00974, "DS",
717283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                             "descriptorSet #%u being bound is not compatible with overlapping descriptorSetLayout "
717355eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                             "at index %u of pipelineLayout 0x%" PRIxLEAST64 " due to: %s. %s",
71749784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                                             set_idx, set_idx + firstSet, reinterpret_cast<uint64_t &>(layout), errorString.c_str(),
717555eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                             validation_error_map[VALIDATION_ERROR_00974]);
7176787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                    }
7177dd725b03ae4d1296a722d0ec5c9fe63941cabe4bChris Forbes
71781c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                    auto setDynamicDescriptorCount = descriptor_set->GetDynamicDescriptorCount();
7179dd725b03ae4d1296a722d0ec5c9fe63941cabe4bChris Forbes
71809784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                    pCB->lastBound[pipelineBindPoint].dynamicOffsets[firstSet + set_idx].clear();
7181dd725b03ae4d1296a722d0ec5c9fe63941cabe4bChris Forbes
7182dd725b03ae4d1296a722d0ec5c9fe63941cabe4bChris Forbes                    if (setDynamicDescriptorCount) {
7183787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                        // First make sure we won't overstep bounds of pDynamicOffsets array
7184dd725b03ae4d1296a722d0ec5c9fe63941cabe4bChris Forbes                        if ((totalDynamicDescriptors + setDynamicDescriptorCount) > dynamicOffsetCount) {
718583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                            skip_call |=
7186787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
71879784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                                        VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[set_idx],
71889784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                                        __LINE__, DRAWSTATE_INVALID_DYNAMIC_OFFSET_COUNT, "DS",
7189414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                                        "descriptorSet #%u (0x%" PRIxLEAST64
7190787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                                        ") requires %u dynamicOffsets, but only %u dynamicOffsets are left in pDynamicOffsets "
7191787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                                        "array. There must be one dynamic offset for each dynamic descriptor being bound.",
71929784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                                        set_idx, (uint64_t)pDescriptorSets[set_idx], descriptor_set->GetDynamicDescriptorCount(),
7193787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                                        (dynamicOffsetCount - totalDynamicDescriptors));
7194cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        } else {  // Validate and store dynamic offsets with the set
7195787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                            // Validate Dynamic Offset Minimums
7196787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                            uint32_t cur_dyn_offset = totalDynamicDescriptors;
71971c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                            for (uint32_t d = 0; d < descriptor_set->GetTotalDescriptorCount(); d++) {
71981c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                                if (descriptor_set->GetTypeFromGlobalIndex(d) == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) {
7199787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                                    if (vk_safe_modulo(
7200787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                                            pDynamicOffsets[cur_dyn_offset],
7201b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis                                            dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment) != 0) {
720283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                        skip_call |= log_msg(
7203787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                                            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
720455eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                            VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, VALIDATION_ERROR_00978,
7205cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "DS",
7206cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "vkCmdBindDescriptorSets(): pDynamicOffsets[%d] is %d but must be a multiple of "
7207cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "device limit minUniformBufferOffsetAlignment 0x%" PRIxLEAST64 ". %s",
7208787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                                            cur_dyn_offset, pDynamicOffsets[cur_dyn_offset],
720955eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                            dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment,
721055eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                            validation_error_map[VALIDATION_ERROR_00978]);
7211787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                                    }
7212787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                                    cur_dyn_offset++;
72131c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                                } else if (descriptor_set->GetTypeFromGlobalIndex(d) == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
7214787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                                    if (vk_safe_modulo(
7215787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                                            pDynamicOffsets[cur_dyn_offset],
7216b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis                                            dev_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment) != 0) {
721783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                        skip_call |= log_msg(
7218787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                                            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
721955eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                            VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, VALIDATION_ERROR_00978,
7220cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "DS",
7221cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "vkCmdBindDescriptorSets(): pDynamicOffsets[%d] is %d but must be a multiple of "
7222cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "device limit minStorageBufferOffsetAlignment 0x%" PRIxLEAST64 ". %s",
7223787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                                            cur_dyn_offset, pDynamicOffsets[cur_dyn_offset],
722455eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                            dev_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment,
722555eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                            validation_error_map[VALIDATION_ERROR_00978]);
72265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                    }
7227787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                                    cur_dyn_offset++;
72285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                }
72295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                            }
7230dd725b03ae4d1296a722d0ec5c9fe63941cabe4bChris Forbes
72319784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                            pCB->lastBound[pipelineBindPoint].dynamicOffsets[firstSet + set_idx] =
7232dd725b03ae4d1296a722d0ec5c9fe63941cabe4bChris Forbes                                std::vector<uint32_t>(pDynamicOffsets + totalDynamicDescriptors,
7233dd725b03ae4d1296a722d0ec5c9fe63941cabe4bChris Forbes                                                      pDynamicOffsets + totalDynamicDescriptors + setDynamicDescriptorCount);
7234787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                            // Keep running total of dynamic descriptor count to verify at the end
7235dd725b03ae4d1296a722d0ec5c9fe63941cabe4bChris Forbes                            totalDynamicDescriptors += setDynamicDescriptorCount;
72365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        }
72375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
7238787f29d93dee194c015789cf61c079504c980572Tobin Ehlis                } else {
72399784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
72409784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                                         VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[set_idx],
72419784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                                         __LINE__, DRAWSTATE_INVALID_SET, "DS",
72429784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                                         "Attempt to bind descriptor set 0x%" PRIxLEAST64 " that doesn't exist!",
72439784e78683f658f304062235ceb2dd2c2652c357Karl Schultz                                         (uint64_t)pDescriptorSets[set_idx]);
72445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
724529f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis                skip_call |= ValidateCmd(dev_data, pCB, CMD_BINDDESCRIPTORSETS, "vkCmdBindDescriptorSets()");
72461ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis                UpdateCmdBufferLastCmd(pCB, CMD_BINDDESCRIPTORSETS);
724772d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                // For any previously bound sets, need to set them to "invalid" if they were disturbed by this update
7248cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (firstSet > 0) {  // Check set #s below the first bound set
724972d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                    for (uint32_t i = 0; i < firstSet; ++i) {
725072d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                        if (pCB->lastBound[pipelineBindPoint].boundDescriptorSets[i] &&
725171511c5a10533c910bfe62c3bcf58e2a4054e7acTobin Ehlis                            !verify_set_layout_compatibility(dev_data, pCB->lastBound[pipelineBindPoint].boundDescriptorSets[i],
725269b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                                                             pipeline_layout, i, errorString)) {
725383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                            skip_call |= log_msg(
725472d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                                dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
725572d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                                VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
725672d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                                (uint64_t)pCB->lastBound[pipelineBindPoint].boundDescriptorSets[i], __LINE__, DRAWSTATE_NONE, "DS",
7257d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen                                "DescriptorSet 0x%" PRIxLEAST64
7258414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                                " previously bound as set #%u was disturbed by newly bound pipelineLayout (0x%" PRIxLEAST64 ")",
725972d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                                (uint64_t)pCB->lastBound[pipelineBindPoint].boundDescriptorSets[i], i, (uint64_t)layout);
726072d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                            pCB->lastBound[pipelineBindPoint].boundDescriptorSets[i] = VK_NULL_HANDLE;
726172d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                        }
726272d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                    }
726372d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                }
726472d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                // Check if newly last bound set invalidates any remaining bound sets
726572d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                if ((pCB->lastBound[pipelineBindPoint].boundDescriptorSets.size() - 1) > (lastSetIndex)) {
726672d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                    if (oldFinalBoundSet &&
726769b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                        !verify_set_layout_compatibility(dev_data, oldFinalBoundSet, pipeline_layout, lastSetIndex, errorString)) {
726871511c5a10533c910bfe62c3bcf58e2a4054e7acTobin Ehlis                        auto old_set = oldFinalBoundSet->GetSet();
726983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                        skip_call |=
727072d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                            log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
727171511c5a10533c910bfe62c3bcf58e2a4054e7acTobin Ehlis                                    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, reinterpret_cast<uint64_t &>(old_set), __LINE__,
7272d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen                                    DRAWSTATE_NONE, "DS", "DescriptorSet 0x%" PRIxLEAST64
7273414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                                                          " previously bound as set #%u is incompatible with set 0x%" PRIxLEAST64
727472d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                                                          " newly bound as set #%u so set #%u and any subsequent sets were "
7275414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                                                          "disturbed by newly bound pipelineLayout (0x%" PRIxLEAST64 ")",
727671511c5a10533c910bfe62c3bcf58e2a4054e7acTobin Ehlis                                    reinterpret_cast<uint64_t &>(old_set), lastSetIndex,
727772d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                                    (uint64_t)pCB->lastBound[pipelineBindPoint].boundDescriptorSets[lastSetIndex], lastSetIndex,
727872d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                                    lastSetIndex + 1, (uint64_t)layout);
727972d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                        pCB->lastBound[pipelineBindPoint].boundDescriptorSets.resize(lastSetIndex + 1);
72805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
72815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
72825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
7283787f29d93dee194c015789cf61c079504c980572Tobin Ehlis            //  dynamicOffsetCount must equal the total number of dynamic descriptors in the sets being bound
7284787f29d93dee194c015789cf61c079504c980572Tobin Ehlis            if (totalDynamicDescriptors != dynamicOffsetCount) {
728583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                skip_call |=
728683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
728755eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                            (uint64_t)commandBuffer, __LINE__, VALIDATION_ERROR_00975, "DS",
728883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                            "Attempting to bind %u descriptorSets with %u dynamic descriptors, but dynamicOffsetCount "
728955eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                            "is %u. It should exactly match the number of dynamic descriptors. %s",
729055eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                            setCount, totalDynamicDescriptors, dynamicOffsetCount, validation_error_map[VALIDATION_ERROR_00975]);
7291787f29d93dee194c015789cf61c079504c980572Tobin Ehlis            }
72925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
729383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdBindDescriptorSets()");
72945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
72955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7296b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
729783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (!skip_call)
72984a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdBindDescriptorSets(commandBuffer, pipelineBindPoint, layout, firstSet, setCount,
72994a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                       pDescriptorSets, dynamicOffsetCount, pDynamicOffsets);
73005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
73015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7302bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBindIndexBuffer(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
7303bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              VkIndexType indexType) {
730483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
730556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7306593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis    // TODO : Somewhere need to verify that IBs have correct usage state flagged
7307b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7308b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski
73099a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto buffer_state = GetBufferState(dev_data, buffer);
73109a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
73115cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (cb_node && buffer_state) {
731235ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis        skip_call |= ValidateMemoryIsBoundToBuffer(dev_data, buffer_state, "vkCmdBindIndexBuffer()", VALIDATION_ERROR_02543);
7313ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        std::function<bool()> function = [=]() {
73145cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            return ValidateBufferMemoryIsValid(dev_data, buffer_state, "vkCmdBindIndexBuffer()");
7315ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        };
73169f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
731729f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, cb_node, CMD_BINDINDEXBUFFER, "vkCmdBindIndexBuffer()");
73181ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(cb_node, CMD_BINDINDEXBUFFER);
73195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        VkDeviceSize offset_align = 0;
73205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        switch (indexType) {
7321cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_INDEX_TYPE_UINT16:
7322cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                offset_align = 2;
7323cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
7324cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_INDEX_TYPE_UINT32:
7325cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                offset_align = 4;
7326cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
7327cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
7328cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // ParamChecker should catch bad enum, we'll also throw alignment error below if offset_align stays 0
7329cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
73305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
73315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!offset_align || (offset % offset_align)) {
733283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
733383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 DRAWSTATE_VTX_INDEX_ALIGNMENT_ERROR, "DS",
733483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 "vkCmdBindIndexBuffer() offset (0x%" PRIxLEAST64 ") does not fall on alignment (%s) boundary.",
733583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 offset, string_VkIndexType(indexType));
73365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
73379f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->status |= CBSTATUS_INDEX_BUFFER_BOUND;
7338ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
7339ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
73405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7341b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7342cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdBindIndexBuffer(commandBuffer, buffer, offset, indexType);
73435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
73445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
73455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisvoid updateResourceTracking(GLOBAL_CB_NODE *pCB, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer *pBuffers) {
73465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t end = firstBinding + bindingCount;
73475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB->currentDrawData.buffers.size() < end) {
73485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->currentDrawData.buffers.resize(end);
73495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
73505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < bindingCount; ++i) {
73515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->currentDrawData.buffers[i + firstBinding] = pBuffers[i];
73525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
73535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
73545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7355e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic inline void updateResourceTrackingOnDraw(GLOBAL_CB_NODE *pCB) { pCB->drawData.push_back(pCB->currentDrawData); }
73565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7357bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBindVertexBuffers(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount,
7358bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkBuffer *pBuffers, const VkDeviceSize *pOffsets) {
735983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
736056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7361593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis    // TODO : Somewhere need to verify that VBs have correct usage state flagged
7362b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7363b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski
73649a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
73659f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis    if (cb_node) {
7366593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        for (uint32_t i = 0; i < bindingCount; ++i) {
73679a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto buffer_state = GetBufferState(dev_data, pBuffers[i]);
73685cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            assert(buffer_state);
736935ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis            skip_call |= ValidateMemoryIsBoundToBuffer(dev_data, buffer_state, "vkCmdBindVertexBuffers()", VALIDATION_ERROR_02546);
7370ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis            std::function<bool()> function = [=]() {
73715cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis                return ValidateBufferMemoryIsValid(dev_data, buffer_state, "vkCmdBindVertexBuffers()");
7372ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis            };
73739f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis            cb_node->validate_functions.push_back(function);
73745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
737529f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, cb_node, CMD_BINDVERTEXBUFFER, "vkCmdBindVertexBuffer()");
73761ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(cb_node, CMD_BINDVERTEXBUFFER);
73779f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        updateResourceTracking(cb_node, firstBinding, bindingCount, pBuffers);
73785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
737983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis        skip_call |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdBindVertexBuffer()");
73805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7381b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7382cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdBindVertexBuffers(commandBuffer, firstBinding, bindingCount, pBuffers, pOffsets);
73835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
73845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
738525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// Expects global_lock to be held by caller
73865569d6457ac22e7d245f3cdee045e71ffbc8b06eTobin Ehlisstatic void MarkStoreImagesAndBuffersAsWritten(layer_data *dev_data, GLOBAL_CB_NODE *pCB) {
73877a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis    for (auto imageView : pCB->updateImages) {
73889a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto view_state = GetImageViewState(dev_data, imageView);
7389cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!view_state) continue;
7390249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis
73919a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto image_state = GetImageState(dev_data, view_state->create_info.image);
73921facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        assert(image_state);
7393e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
73941facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            SetImageMemoryValid(dev_data, image_state, true);
7395e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
73967a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        };
73977a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        pCB->validate_functions.push_back(function);
73987a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis    }
73997a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis    for (auto buffer : pCB->updateBuffers) {
74009a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto buffer_state = GetBufferState(dev_data, buffer);
74015cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        assert(buffer_state);
7402e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
74035cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            SetBufferMemoryValid(dev_data, buffer_state, true);
7404e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
74057a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        };
74067a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        pCB->validate_functions.push_back(function);
74075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
74085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
74095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7410ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis// Generic function to handle validation for all CmdDraw* type functions
7411ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool ValidateCmdDrawType(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed, VkPipelineBindPoint bind_point,
7412ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                CMD_TYPE cmd_type, GLOBAL_CB_NODE **cb_state, const char *caller,
74134f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                UNIQUE_VALIDATION_ERROR_CODE msg_code, UNIQUE_VALIDATION_ERROR_CODE const dynamic_state_msg_code) {
741458b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    bool skip = false;
74159a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *cb_state = GetCBNode(dev_data, cmd_buffer);
741658b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    if (*cb_state) {
7417ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis        skip |= ValidateCmd(dev_data, *cb_state, cmd_type, caller);
74184f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes        skip |= ValidateDrawState(dev_data, *cb_state, indexed, bind_point, caller, dynamic_state_msg_code);
741925d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis        skip |= (VK_PIPELINE_BIND_POINT_GRAPHICS == bind_point) ? outsideRenderPass(dev_data, *cb_state, caller, msg_code)
742025d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis                                                                : insideRenderPass(dev_data, *cb_state, caller, msg_code);
742158b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    }
742258b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    return skip;
742358b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis}
742458b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis
742525d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis// Generic function to handle state update for all CmdDraw* and CmdDispatch* type functions
7426ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void UpdateStateCmdDrawDispatchType(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
7427ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                           CMD_TYPE cmd_type) {
7428ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateDrawState(dev_data, cb_state, bind_point);
74292f921d33544c162dcb726fc3c7b915e89c02ff24Tobin Ehlis    MarkStoreImagesAndBuffersAsWritten(dev_data, cb_state);
74301ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis    UpdateCmdBufferLastCmd(cb_state, cmd_type);
743125d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis}
743225d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis
7433ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis// Generic function to handle state update for all CmdDraw* type functions
7434ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void UpdateStateCmdDrawType(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
7435ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                   CMD_TYPE cmd_type, DRAW_TYPE draw_type) {
7436ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawDispatchType(dev_data, cb_state, bind_point, cmd_type);
7437c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis    updateResourceTrackingOnDraw(cb_state);
7438ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    cb_state->drawCount[draw_type]++;
7439ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis}
7440ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis
7441ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDraw(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed, VkPipelineBindPoint bind_point,
7442ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                   GLOBAL_CB_NODE **cb_state, const char *caller) {
74434f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes    return ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAW, cb_state, caller, VALIDATION_ERROR_01365,
74444f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                               VALIDATION_ERROR_02203);
7445ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis}
7446ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis
7447ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDraw(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point) {
7448ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawType(dev_data, cb_state, bind_point, CMD_DRAW, DRAW);
7449c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis}
7450c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis
745189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount,
745289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                   uint32_t firstVertex, uint32_t firstInstance) {
745356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
745458b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
7455b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7456ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    bool skip = PreCallValidateCmdDraw(dev_data, commandBuffer, false, VK_PIPELINE_BIND_POINT_GRAPHICS, &cb_state, "vkCmdDraw()");
7457b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
745858b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    if (!skip) {
74594a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDraw(commandBuffer, vertexCount, instanceCount, firstVertex, firstInstance);
7460c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis        lock.lock();
7461ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDraw(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS);
7462c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis        lock.unlock();
7463c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis    }
74645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
74655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7466ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDrawIndexed(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed,
7467ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                          VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state, const char *caller) {
74684f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes    return ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAWINDEXED, cb_state, caller, VALIDATION_ERROR_01372,
74694f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                               VALIDATION_ERROR_02216);
7470ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis}
7471ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis
7472ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDrawIndexed(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point) {
7473ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawType(dev_data, cb_state, bind_point, CMD_DRAWINDEXED, DRAW_INDEXED);
7474ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis}
7475ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis
7476bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount,
7477bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                          uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance) {
747856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7479ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
7480b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7481ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    bool skip = PreCallValidateCmdDrawIndexed(dev_data, commandBuffer, true, VK_PIPELINE_BIND_POINT_GRAPHICS, &cb_state,
7482ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                              "vkCmdDrawIndexed()");
7483b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7484ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    if (!skip) {
74854a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDrawIndexed(commandBuffer, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
7486ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis        lock.lock();
7487ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDrawIndexed(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS);
7488ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis        lock.unlock();
7489ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    }
74905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
74915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7492ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDrawIndirect(layer_data *dev_data, VkCommandBuffer cmd_buffer, VkBuffer buffer, bool indexed,
7493ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                           VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state, BUFFER_STATE **buffer_state,
7494ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                           const char *caller) {
74954f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes    bool skip = ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAWINDIRECT, cb_state, caller,
74964f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                    VALIDATION_ERROR_01381, VALIDATION_ERROR_02234);
74979a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *buffer_state = GetBufferState(dev_data, buffer);
749835ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis    skip |= ValidateMemoryIsBoundToBuffer(dev_data, *buffer_state, caller, VALIDATION_ERROR_02544);
7499d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    return skip;
7500d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis}
7501d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis
7502ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDrawIndirect(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
7503ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                          BUFFER_STATE *buffer_state) {
7504ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawType(dev_data, cb_state, bind_point, CMD_DRAWINDIRECT, DRAW_INDIRECT);
7505d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    AddCommandBufferBindingBuffer(dev_data, cb_state, buffer_state);
7506d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis}
7507d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis
7508bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count,
7509bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           uint32_t stride) {
751056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7511d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
7512d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    BUFFER_STATE *buffer_state = nullptr;
7513b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7514872a2f0ca3ffdeddfa7483e777191fa64b853892Tony Barbour    bool skip = PreCallValidateCmdDrawIndirect(dev_data, commandBuffer, buffer, false, VK_PIPELINE_BIND_POINT_GRAPHICS, &cb_state,
7515ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                               &buffer_state, "vkCmdDrawIndirect()");
7516b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7517d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    if (!skip) {
75184a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDrawIndirect(commandBuffer, buffer, offset, count, stride);
7519d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis        lock.lock();
7520ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDrawIndirect(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, buffer_state);
7521d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis        lock.unlock();
7522d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    }
75235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
75245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7525ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDrawIndexedIndirect(layer_data *dev_data, VkCommandBuffer cmd_buffer, VkBuffer buffer, bool indexed,
7526ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                  VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state,
7527ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                  BUFFER_STATE **buffer_state, const char *caller) {
7528ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    bool skip = ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAWINDEXEDINDIRECT, cb_state, caller,
75294f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                    VALIDATION_ERROR_01393, VALIDATION_ERROR_02272);
75309a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *buffer_state = GetBufferState(dev_data, buffer);
753135ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis    skip |= ValidateMemoryIsBoundToBuffer(dev_data, *buffer_state, caller, VALIDATION_ERROR_02545);
75320c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    return skip;
75330c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis}
75340c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis
7535ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDrawIndexedIndirect(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
7536ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                 BUFFER_STATE *buffer_state) {
7537ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawType(dev_data, cb_state, bind_point, CMD_DRAWINDEXEDINDIRECT, DRAW_INDEXED_INDIRECT);
75380c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    AddCommandBufferBindingBuffer(dev_data, cb_state, buffer_state);
75390c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis}
75400c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis
7541bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
7542bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                  uint32_t count, uint32_t stride) {
754356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
75440c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
75450c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    BUFFER_STATE *buffer_state = nullptr;
7546b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
75470c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    bool skip = PreCallValidateCmdDrawIndexedIndirect(dev_data, commandBuffer, buffer, true, VK_PIPELINE_BIND_POINT_GRAPHICS,
7548ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                      &cb_state, &buffer_state, "vkCmdDrawIndexedIndirect()");
7549b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
75500c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    if (!skip) {
75514a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDrawIndexedIndirect(commandBuffer, buffer, offset, count, stride);
75520c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis        lock.lock();
7553ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDrawIndexedIndirect(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, buffer_state);
75540c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis        lock.unlock();
75550c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    }
75565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
75575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7558ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDispatch(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed,
7559ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                       VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state, const char *caller) {
75604f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes    return ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DISPATCH, cb_state, caller, VALIDATION_ERROR_01562,
75614f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                               VALIDATION_ERROR_UNDEFINED);
756225d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis}
756325d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis
7564ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDispatch(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point) {
7565ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawDispatchType(dev_data, cb_state, bind_point, CMD_DISPATCH);
756625d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis}
756725d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis
756889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z) {
756956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
757025d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
7571b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7572ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    bool skip =
7573ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PreCallValidateCmdDispatch(dev_data, commandBuffer, false, VK_PIPELINE_BIND_POINT_COMPUTE, &cb_state, "vkCmdDispatch()");
7574b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
757525d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis    if (!skip) {
75764a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDispatch(commandBuffer, x, y, z);
757725d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis        lock.lock();
7578ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDispatch(dev_data, cb_state, VK_PIPELINE_BIND_POINT_COMPUTE);
757925d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis        lock.unlock();
758025d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis    }
75815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
75825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7583ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDispatchIndirect(layer_data *dev_data, VkCommandBuffer cmd_buffer, VkBuffer buffer, bool indexed,
7584ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                               VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state,
7585ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                               BUFFER_STATE **buffer_state, const char *caller) {
7586ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    bool skip = ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DISPATCHINDIRECT, cb_state, caller,
75874f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                    VALIDATION_ERROR_01569, VALIDATION_ERROR_UNDEFINED);
75889a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *buffer_state = GetBufferState(dev_data, buffer);
758935ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis    skip |= ValidateMemoryIsBoundToBuffer(dev_data, *buffer_state, caller, VALIDATION_ERROR_02547);
759079c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    return skip;
759179c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis}
759279c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis
7593ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDispatchIndirect(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
7594ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                              BUFFER_STATE *buffer_state) {
7595ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawDispatchType(dev_data, cb_state, bind_point, CMD_DISPATCHINDIRECT);
759679c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    AddCommandBufferBindingBuffer(dev_data, cb_state, buffer_state);
759779c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis}
759879c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis
7599bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset) {
760056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
760179c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
760279c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    BUFFER_STATE *buffer_state = nullptr;
7603b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
76047433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis    bool skip = PreCallValidateCmdDispatchIndirect(dev_data, commandBuffer, buffer, false, VK_PIPELINE_BIND_POINT_COMPUTE,
7605ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                   &cb_state, &buffer_state, "vkCmdDispatchIndirect()");
7606b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
760779c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    if (!skip) {
76084a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDispatchIndirect(commandBuffer, buffer, offset);
760979c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis        lock.lock();
7610ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDispatchIndirect(dev_data, cb_state, VK_PIPELINE_BIND_POINT_COMPUTE, buffer_state);
761179c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis        lock.unlock();
761279c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    }
76135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
76145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
761589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
761689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                         uint32_t regionCount, const VkBufferCopy *pRegions) {
7617c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7618b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7619ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
7620c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski    auto cb_node = GetCBNode(device_data, commandBuffer);
7621c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski    auto src_buffer_state = GetBufferState(device_data, srcBuffer);
7622c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski    auto dst_buffer_state = GetBufferState(device_data, dstBuffer);
7623593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
7624c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski    if (cb_node && src_buffer_state && dst_buffer_state) {
7625c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski        bool skip = PreCallValidateCmdCopyBuffer(device_data, cb_node, src_buffer_state, dst_buffer_state);
7626c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski        if (!skip) {
7627c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski            PreCallRecordCmdCopyBuffer(device_data, cb_node, src_buffer_state, dst_buffer_state);
7628c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski            lock.unlock();
7629c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski            device_data->dispatch_table.CmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, regionCount, pRegions);
7630c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski        }
7631ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
7632c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski        lock.unlock();
7633ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
76345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
76355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
76365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7637bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
7638bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
7639bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        const VkImageCopy *pRegions) {
76406a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    bool skip = false;
76416a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7642b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7643249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis
76446a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    auto cb_node = GetCBNode(device_data, commandBuffer);
76456a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    auto src_image_state = GetImageState(device_data, srcImage);
76466a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    auto dst_image_state = GetImageState(device_data, dstImage);
76471facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (cb_node && src_image_state && dst_image_state) {
76486a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski        skip = PreCallValidateCmdCopyImage(device_data, cb_node, src_image_state, dst_image_state, regionCount, pRegions,
76496a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski                                           srcImageLayout, dstImageLayout);
76506a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski        if (!skip) {
76516a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski            PreCallRecordCmdCopyImage(device_data, cb_node, src_image_state, dst_image_state);
76526a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski            lock.unlock();
76536a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski            device_data->dispatch_table.CmdCopyImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
76546a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski                                                     pRegions);
76555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7656249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis    } else {
76576a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski        lock.unlock();
7658249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis        assert(0);
76595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
76605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
76615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7662eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski// Validate that an image's sampleCount matches the requirement for a specific API call
766360568995aca225f81acda8ce40cfabbea2c19397Mark Lobodzinskibool ValidateImageSampleCount(layer_data *dev_data, IMAGE_STATE *image_state, VkSampleCountFlagBits sample_count,
766460568995aca225f81acda8ce40cfabbea2c19397Mark Lobodzinski                              const char *location, UNIQUE_VALIDATION_ERROR_CODE msgCode) {
7665eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski    bool skip = false;
76661facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (image_state->createInfo.samples != sample_count) {
766755eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen        skip =
766855eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
766955eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                    reinterpret_cast<uint64_t &>(image_state->image), 0, msgCode, "DS",
767055eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                    "%s for image 0x%" PRIxLEAST64 " was created with a sample count of %s but must be %s. %s", location,
767155eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                    reinterpret_cast<uint64_t &>(image_state->image), string_VkSampleCountFlagBits(image_state->createInfo.samples),
767255eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                    string_VkSampleCountFlagBits(sample_count), validation_error_map[msgCode]);
7673eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski    }
7674eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski    return skip;
7675eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski}
7676eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski
7677bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
7678bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
7679bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        const VkImageBlit *pRegions, VkFilter filter) {
768056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7681b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7682593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
76839a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
76849a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto src_image_state = GetImageState(dev_data, srcImage);
76859a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto dst_image_state = GetImageState(dev_data, dstImage);
76860dc51740dbd7b9f0ba7c071e0bf96f63d6d48c85Mark Lobodzinski
7687055112ec99304db71d55b69a60e1da14e8af8f60Mark Lobodzinski    bool skip = PreCallValidateCmdBlitImage(dev_data, cb_node, src_image_state, dst_image_state, regionCount, pRegions, filter);
76880dc51740dbd7b9f0ba7c071e0bf96f63d6d48c85Mark Lobodzinski
7689dca02371c9531e7a9a2a51decae1db4d297862c4Mark Lobodzinski    if (!skip) {
7690eebd811afd800663f15fda8fc71bc203a03fe294Mark Lobodzinski        PreCallRecordCmdBlitImage(dev_data, cb_node, src_image_state, dst_image_state);
7691eebd811afd800663f15fda8fc71bc203a03fe294Mark Lobodzinski        lock.unlock();
76924a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdBlitImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
76934a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                              pRegions, filter);
76940dc51740dbd7b9f0ba7c071e0bf96f63d6d48c85Mark Lobodzinski    }
76955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
76965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7697bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage,
7698bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                VkImageLayout dstImageLayout, uint32_t regionCount,
7699bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkBufferImageCopy *pRegions) {
770083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
770156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7702b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7703593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
77049a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
77059a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto src_buff_state = GetBufferState(dev_data, srcBuffer);
77069a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto dst_image_state = GetImageState(dev_data, dstImage);
77075cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (cb_node && src_buff_state && dst_image_state) {
770855eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen        skip_call |= ValidateImageSampleCount(dev_data, dst_image_state, VK_SAMPLE_COUNT_1_BIT,
770955eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                              "vkCmdCopyBufferToImage(): dstImage", VALIDATION_ERROR_01232);
771035ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis        skip_call |= ValidateMemoryIsBoundToBuffer(dev_data, src_buff_state, "vkCmdCopyBufferToImage()", VALIDATION_ERROR_02535);
771135ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis        skip_call |= ValidateMemoryIsBoundToImage(dev_data, dst_image_state, "vkCmdCopyBufferToImage()", VALIDATION_ERROR_02536);
77125cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        AddCommandBufferBindingBuffer(dev_data, cb_node, src_buff_state);
77131facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        AddCommandBufferBindingImage(dev_data, cb_node, dst_image_state);
77141b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes        skip_call |=
77155cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            ValidateBufferUsageFlags(dev_data, src_buff_state, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, true, VALIDATION_ERROR_01230,
77161b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes                                     "vkCmdCopyBufferToImage()", "VK_BUFFER_USAGE_TRANSFER_SRC_BIT");
77171facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        skip_call |= ValidateImageUsageFlags(dev_data, dst_image_state, VK_IMAGE_USAGE_TRANSFER_DST_BIT, true,
77181b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes                                             VALIDATION_ERROR_01231, "vkCmdCopyBufferToImage()", "VK_IMAGE_USAGE_TRANSFER_DST_BIT");
7719e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
77201facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            SetImageMemoryValid(dev_data, dst_image_state, true);
7721e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
77225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        };
77239f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
77245cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        function = [=]() { return ValidateBufferMemoryIsValid(dev_data, src_buff_state, "vkCmdCopyBufferToImage()"); };
77259f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
7726593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
772729f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, cb_node, CMD_COPYBUFFERTOIMAGE, "vkCmdCopyBufferToImage()");
77281ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(cb_node, CMD_COPYBUFFERTOIMAGE);
7729ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen        skip_call |= insideRenderPass(dev_data, cb_node, "vkCmdCopyBufferToImage()", VALIDATION_ERROR_01242);
77305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < regionCount; ++i) {
773155eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen            skip_call |= VerifyDestImageLayout(dev_data, cb_node, dstImage, pRegions[i].imageSubresource, dstImageLayout,
773255eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                               VALIDATION_ERROR_01234);
77331facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            skip_call |= ValidateCopyBufferImageTransferGranularityRequirements(dev_data, cb_node, dst_image_state, &pRegions[i], i,
77349ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                                                                                "vkCmdCopyBufferToImage()");
77355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7736ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
7737ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
77385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7739b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
774083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (!skip_call)
77414a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdCopyBufferToImage(commandBuffer, srcBuffer, dstImage, dstImageLayout, regionCount, pRegions);
77425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
77435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7744bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
7745bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy *pRegions) {
774683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
774756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7748b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7749593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
77509a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
77519a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto src_image_state = GetImageState(dev_data, srcImage);
77529a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto dst_buff_state = GetBufferState(dev_data, dstBuffer);
77535cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (cb_node && src_image_state && dst_buff_state) {
775455eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen        skip_call |= ValidateImageSampleCount(dev_data, src_image_state, VK_SAMPLE_COUNT_1_BIT,
775555eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                              "vkCmdCopyImageToBuffer(): srcImage", VALIDATION_ERROR_01249);
775635ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis        skip_call |= ValidateMemoryIsBoundToImage(dev_data, src_image_state, "vkCmdCopyImageToBuffer()", VALIDATION_ERROR_02537);
775735ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis        skip_call |= ValidateMemoryIsBoundToBuffer(dev_data, dst_buff_state, "vkCmdCopyImageToBuffer()", VALIDATION_ERROR_02538);
7758249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis        // Update bindings between buffer/image and cmd buffer
77591facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        AddCommandBufferBindingImage(dev_data, cb_node, src_image_state);
77605cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        AddCommandBufferBindingBuffer(dev_data, cb_node, dst_buff_state);
7761249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis        // Validate that SRC image & DST buffer have correct usage flags set
77621facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        skip_call |= ValidateImageUsageFlags(dev_data, src_image_state, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true,
77631b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes                                             VALIDATION_ERROR_01248, "vkCmdCopyImageToBuffer()", "VK_IMAGE_USAGE_TRANSFER_SRC_BIT");
77641b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes        skip_call |=
77655cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            ValidateBufferUsageFlags(dev_data, dst_buff_state, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, VALIDATION_ERROR_01252,
77661b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes                                     "vkCmdCopyImageToBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
7767e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
77681facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            return ValidateImageMemoryIsValid(dev_data, src_image_state, "vkCmdCopyImageToBuffer()");
7769e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        };
77709f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
7771593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        function = [=]() {
77725cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            SetBufferMemoryValid(dev_data, dst_buff_state, true);
7773e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
77745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        };
77759f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
7776593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
777729f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, cb_node, CMD_COPYIMAGETOBUFFER, "vkCmdCopyImageToBuffer()");
77781ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(cb_node, CMD_COPYIMAGETOBUFFER);
7779ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen        skip_call |= insideRenderPass(dev_data, cb_node, "vkCmdCopyImageToBuffer()", VALIDATION_ERROR_01260);
77805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < regionCount; ++i) {
778155eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen            skip_call |= VerifySourceImageLayout(dev_data, cb_node, srcImage, pRegions[i].imageSubresource, srcImageLayout,
778255eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                                 VALIDATION_ERROR_01251);
77831facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            skip_call |= ValidateCopyBufferImageTransferGranularityRequirements(dev_data, cb_node, src_image_state, &pRegions[i], i,
77849ecb1daf727b16dfa6a26236bd93cd75f4d12696Gregory Mitrano                                                                                "CmdCopyImageToBuffer");
77855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7786ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
7787ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
77885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7789b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
779083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (!skip_call)
77914a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdCopyImageToBuffer(commandBuffer, srcImage, srcImageLayout, dstBuffer, regionCount, pRegions);
77925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
77935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7794bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
7795bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           VkDeviceSize dataSize, const uint32_t *pData) {
779683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
779756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7798b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7799593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
78009a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
78019a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto dst_buff_state = GetBufferState(dev_data, dstBuffer);
78025cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (cb_node && dst_buff_state) {
780335ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis        skip_call |= ValidateMemoryIsBoundToBuffer(dev_data, dst_buff_state, "vkCmdUpdateBuffer()", VALIDATION_ERROR_02530);
7804ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Update bindings between buffer and cmd buffer
78055cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        AddCommandBufferBindingBuffer(dev_data, cb_node, dst_buff_state);
7806ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Validate that DST buffer has correct usage flags set
78075cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        skip_call |= ValidateBufferUsageFlags(dev_data, dst_buff_state, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true,
78081b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes                                              VALIDATION_ERROR_01146, "vkCmdUpdateBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
7809e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
78105cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            SetBufferMemoryValid(dev_data, dst_buff_state, true);
7811e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
78125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        };
78139f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
7814593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
781529f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, cb_node, CMD_UPDATEBUFFER, "vkCmdUpdateBuffer()");
78161ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(cb_node, CMD_UPDATEBUFFER);
7817ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen        skip_call |= insideRenderPass(dev_data, cb_node, "vkCmdUpdateBuffer()", VALIDATION_ERROR_01155);
7818ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
7819ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
78205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7821b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7822cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdUpdateBuffer(commandBuffer, dstBuffer, dstOffset, dataSize, pData);
78235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
78245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7825bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
7826bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         VkDeviceSize size, uint32_t data) {
782723bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7828b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
782923bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski    auto cb_node = GetCBNode(device_data, commandBuffer);
783023bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski    auto buffer_state = GetBufferState(device_data, dstBuffer);
7831593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
783223bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski    if (cb_node && buffer_state) {
783323bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski        bool skip = PreCallValidateCmdFillBuffer(device_data, cb_node, buffer_state);
783423bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski        if (!skip) {
783523bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski            PreCallRecordCmdFillBuffer(device_data, cb_node, buffer_state);
783623bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski            lock.unlock();
783723bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski            device_data->dispatch_table.CmdFillBuffer(commandBuffer, dstBuffer, dstOffset, size, data);
783823bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski        }
7839ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
784023bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski        lock.unlock();
7841ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
78425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
78435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
78445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
78454028af23e688ab5730f48ab2244dd042e2eefaedMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount,
78464028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski                                               const VkClearAttachment *pAttachments, uint32_t rectCount,
78474028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski                                               const VkClearRect *pRects) {
78484028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski    bool skip = false;
784956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
78504028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski    {
78514028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski        std::lock_guard<std::mutex> lock(global_lock);
78524028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski        skip = PreCallValidateCmdClearAttachments(dev_data, commandBuffer, attachmentCount, pAttachments, rectCount, pRects);
78534028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski    }
7854cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdClearAttachments(commandBuffer, attachmentCount, pAttachments, rectCount, pRects);
78555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
78565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
78570482c55760707900fcd072f6895c121bcf055f6eMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
78580482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski                                              const VkClearColorValue *pColor, uint32_t rangeCount,
78590482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski                                              const VkImageSubresourceRange *pRanges) {
786056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7861b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
78620482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski
78630482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    bool skip = PreCallValidateCmdClearColorImage(dev_data, commandBuffer, image, imageLayout, rangeCount, pRanges);
78640482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    if (!skip) {
78650482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        PreCallRecordCmdClearImage(dev_data, commandBuffer, image, imageLayout, rangeCount, pRanges, CMD_CLEARCOLORIMAGE);
78660482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        lock.unlock();
78670482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        dev_data->dispatch_table.CmdClearColorImage(commandBuffer, image, imageLayout, pColor, rangeCount, pRanges);
78680482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    }
78690482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski}
78700482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski
78710482c55760707900fcd072f6895c121bcf055f6eMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
78720482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski                                                     const VkClearDepthStencilValue *pDepthStencil, uint32_t rangeCount,
78730482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski                                                     const VkImageSubresourceRange *pRanges) {
787456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
78750482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    std::unique_lock<std::mutex> lock(global_lock);
78760482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski
78770482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    bool skip = PreCallValidateCmdClearDepthStencilImage(dev_data, commandBuffer, image, imageLayout, rangeCount, pRanges);
78780482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    if (!skip) {
78790482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        PreCallRecordCmdClearImage(dev_data, commandBuffer, image, imageLayout, rangeCount, pRanges, CMD_CLEARDEPTHSTENCILIMAGE);
78800482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        lock.unlock();
78810482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        dev_data->dispatch_table.CmdClearDepthStencilImage(commandBuffer, image, imageLayout, pDepthStencil, rangeCount, pRanges);
78827f8aa8f5abceedbb599ef69af1dfbb38c0df2660Slawomir Cygan    }
78835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
78845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7885bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
7886bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
7887bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           const VkImageResolve *pRegions) {
788856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7889b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7890593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
78919a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
78929a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto src_image_state = GetImageState(dev_data, srcImage);
78939a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto dst_image_state = GetImageState(dev_data, dstImage);
789409fe5ac5edaec7f0dbcc9fd696e68194569aea89Mark Lobodzinski
789525f7873c9ce3ed39d18bba8750d7538905e150dfMark Lobodzinski    bool skip = PreCallValidateCmdResolveImage(dev_data, cb_node, src_image_state, dst_image_state, regionCount, pRegions);
789609fe5ac5edaec7f0dbcc9fd696e68194569aea89Mark Lobodzinski
789709fe5ac5edaec7f0dbcc9fd696e68194569aea89Mark Lobodzinski    if (!skip) {
78986c0400e625554ce7fddb833eeace0de19cfcc965Mark Lobodzinski        PreCallRecordCmdResolveImage(dev_data, cb_node, src_image_state, dst_image_state);
78996c0400e625554ce7fddb833eeace0de19cfcc965Mark Lobodzinski        lock.unlock();
79004a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdResolveImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
79014a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                 pRegions);
790209fe5ac5edaec7f0dbcc9fd696e68194569aea89Mark Lobodzinski    }
79035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
79045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7905b06379a335598a3d8c53c694e875dda19eeab612Mark LobodzinskiVKAPI_ATTR void VKAPI_CALL GetImageSubresourceLayout(VkDevice device, VkImage image, const VkImageSubresource *pSubresource,
7906b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski    VkSubresourceLayout *pLayout) {
7907b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski    bool skipCall = false;
790856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
7909b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski    VkFormat format;
7910b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski
79119a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto imageEntry = GetImageState(device_data, image);
7912b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski
7913b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski    // Validate that image aspects match formats
7914b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski    if (imageEntry) {
7915b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski        format = imageEntry->createInfo.format;
7916b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski        if (vk_format_is_color(format)) {
7917b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski            if (pSubresource->aspectMask != VK_IMAGE_ASPECT_COLOR_BIT) {
7918b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski                std::stringstream ss;
7919b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski                ss << "vkGetImageSubresourceLayout: For color formats, the aspectMask field of VkImageSubresource must be "
7920b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski                    "VK_IMAGE_ASPECT_COLOR.";
7921b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski                skipCall |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
7922b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski                    (uint64_t)image, __LINE__, VALIDATION_ERROR_00741, "IMAGE", "%s. %s", ss.str().c_str(),
7923b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski                    validation_error_map[VALIDATION_ERROR_00741]);
7924b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski            }
7925b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski        } else if (vk_format_is_depth_or_stencil(format)) {
7926b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski            if ((pSubresource->aspectMask != VK_IMAGE_ASPECT_DEPTH_BIT) &&
7927b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski                (pSubresource->aspectMask != VK_IMAGE_ASPECT_STENCIL_BIT)) {
7928b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski                std::stringstream ss;
7929b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski                ss << "vkGetImageSubresourceLayout: For depth/stencil formats, the aspectMask selects either the depth or stencil "
7930b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski                    "image aspectMask.";
7931b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski                skipCall |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
7932b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski                    (uint64_t)image, __LINE__, VALIDATION_ERROR_00741, "IMAGE", "%s. %s", ss.str().c_str(),
7933b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski                    validation_error_map[VALIDATION_ERROR_00741]);
7934b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski            }
7935b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski        }
7936b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski    }
7937b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski
7938b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski    if (!skipCall) {
7939b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski        device_data->dispatch_table.GetImageSubresourceLayout(device, image, pSubresource, pLayout);
7940b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski    }
7941b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski}
7942b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski
7943b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentinebool setEventStageMask(VkQueue queue, VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
794456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
79459a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
7946b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    if (pCB) {
7947b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        pCB->eventToStageMap[event] = stageMask;
7948b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
7949b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    auto queue_data = dev_data->queueMap.find(queue);
7950b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    if (queue_data != dev_data->queueMap.end()) {
7951b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        queue_data->second.eventToStageMap[event] = stageMask;
7952b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
7953b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    return false;
7954b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine}
7955b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine
7956bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
795783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
795856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7959b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
79609a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
79615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
796229f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETEVENT, "vkCmdSetEvent()");
79631ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETEVENT);
7964ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen        skip_call |= insideRenderPass(dev_data, pCB, "vkCmdSetEvent()", VALIDATION_ERROR_00238);
7965208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip_call |=
7966208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis            ValidateStageMaskGsTsEnables(dev_data, stageMask, "vkCmdSetEvent()", VALIDATION_ERROR_00230, VALIDATION_ERROR_00231);
79679a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto event_state = GetEventNode(dev_data, event);
79684710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        if (event_state) {
79694710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis            addCommandBufferBinding(&event_state->cb_bindings,
7970ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis                                    {reinterpret_cast<uint64_t &>(event), VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT}, pCB);
79714710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis            event_state->cb_bindings.insert(pCB);
7972ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis        }
79735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->events.push_back(event);
7974c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine        if (!pCB->waitedEvents.count(event)) {
7975c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine            pCB->writeEventsBeforeWait.push_back(event);
7976c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine        }
7977b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        std::function<bool(VkQueue)> eventUpdate =
7978b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            std::bind(setEventStageMask, std::placeholders::_1, commandBuffer, event, stageMask);
7979b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        pCB->eventUpdates.push_back(eventUpdate);
79805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7981b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7982cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetEvent(commandBuffer, event, stageMask);
79835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
79845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7985bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdResetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
798683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
798756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7988b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
79899a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
79905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
799129f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_RESETEVENT, "vkCmdResetEvent()");
79921ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_RESETEVENT);
7993ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen        skip_call |= insideRenderPass(dev_data, pCB, "vkCmdResetEvent()", VALIDATION_ERROR_00249);
7994208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip_call |=
7995208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis            ValidateStageMaskGsTsEnables(dev_data, stageMask, "vkCmdResetEvent()", VALIDATION_ERROR_00240, VALIDATION_ERROR_00241);
79969a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto event_state = GetEventNode(dev_data, event);
79974710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        if (event_state) {
79984710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis            addCommandBufferBinding(&event_state->cb_bindings,
7999ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis                                    {reinterpret_cast<uint64_t &>(event), VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT}, pCB);
80004710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis            event_state->cb_bindings.insert(pCB);
8001ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis        }
80025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->events.push_back(event);
8003c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine        if (!pCB->waitedEvents.count(event)) {
8004c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine            pCB->writeEventsBeforeWait.push_back(event);
8005c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine        }
8006208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        // TODO : Add check for VALIDATION_ERROR_00226
8007b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        std::function<bool(VkQueue)> eventUpdate =
8008b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            std::bind(setEventStageMask, std::placeholders::_1, commandBuffer, event, VkPipelineStageFlags(0));
8009b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        pCB->eventUpdates.push_back(eventUpdate);
80105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8011b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8012cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdResetEvent(commandBuffer, event, stageMask);
80135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
80145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8015e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool ValidateBarriers(const char *funcName, VkCommandBuffer cmdBuffer, uint32_t memBarrierCount,
8016e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                             const VkMemoryBarrier *pMemBarriers, uint32_t bufferBarrierCount,
8017e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                             const VkBufferMemoryBarrier *pBufferMemBarriers, uint32_t imageMemBarrierCount,
8018e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                             const VkImageMemoryBarrier *pImageMemBarriers) {
8019a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis    bool skip = false;
802056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(cmdBuffer), layer_data_map);
80219a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, cmdBuffer);
80225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB->activeRenderPass && memBarrierCount) {
8023ee691f5c5fa87aac3750454d2bca2cb582e4e817Chris Forbes        if (!pCB->activeRenderPass->hasSelfDependency[pCB->activeSubpass]) {
8024a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8025cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            DRAWSTATE_INVALID_BARRIER, "DS",
8026cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s: Barriers cannot be set during subpass %d "
8027cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "with no self dependency specified.",
8028a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            funcName, pCB->activeSubpass);
80295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
80305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
80315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < imageMemBarrierCount; ++i) {
80325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto mem_barrier = &pImageMemBarriers[i];
80339a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto image_data = GetImageState(dev_data, mem_barrier->image);
80346d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis        if (image_data) {
80355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t src_q_f_index = mem_barrier->srcQueueFamilyIndex;
80365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t dst_q_f_index = mem_barrier->dstQueueFamilyIndex;
80376d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            if (image_data->createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) {
80385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // srcQueueFamilyIndex and dstQueueFamilyIndex must both
80395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // be VK_QUEUE_FAMILY_IGNORED
80405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if ((src_q_f_index != VK_QUEUE_FAMILY_IGNORED) || (dst_q_f_index != VK_QUEUE_FAMILY_IGNORED)) {
8041cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip |=
8042cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8043cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                DRAWSTATE_INVALID_QUEUE_INDEX, "DS", "%s: Image Barrier for image 0x%" PRIx64
8044cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                                     " was created with sharingMode of "
8045cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                                     "VK_SHARING_MODE_CONCURRENT. Src and dst "
8046cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                                     "queueFamilyIndices must be VK_QUEUE_FAMILY_IGNORED.",
8047cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                funcName, reinterpret_cast<const uint64_t &>(mem_barrier->image));
80485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
80495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else {
80505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // Sharing mode is VK_SHARING_MODE_EXCLUSIVE. srcQueueFamilyIndex and
80515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // dstQueueFamilyIndex must either both be VK_QUEUE_FAMILY_IGNORED,
80525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // or both be a valid queue family
80535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (((src_q_f_index == VK_QUEUE_FAMILY_IGNORED) || (dst_q_f_index == VK_QUEUE_FAMILY_IGNORED)) &&
80545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    (src_q_f_index != dst_q_f_index)) {
8055a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                    skip |=
80565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8057cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                DRAWSTATE_INVALID_QUEUE_INDEX, "DS", "%s: Image 0x%" PRIx64
8058cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                                     " was created with sharingMode "
80595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                                     "of VK_SHARING_MODE_EXCLUSIVE. If one of src- or "
80605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                                     "dstQueueFamilyIndex is VK_QUEUE_FAMILY_IGNORED, both "
80615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                                     "must be.",
80625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                funcName, reinterpret_cast<const uint64_t &>(mem_barrier->image));
80635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                } else if (((src_q_f_index != VK_QUEUE_FAMILY_IGNORED) && (dst_q_f_index != VK_QUEUE_FAMILY_IGNORED)) &&
8064b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis                           ((src_q_f_index >= dev_data->phys_dev_properties.queue_family_properties.size()) ||
8065b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis                            (dst_q_f_index >= dev_data->phys_dev_properties.queue_family_properties.size()))) {
8066a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
8067a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                    __LINE__, DRAWSTATE_INVALID_QUEUE_INDEX, "DS",
8068cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    "%s: Image 0x%" PRIx64
8069cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    " was created with sharingMode "
8070a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                    "of VK_SHARING_MODE_EXCLUSIVE, but srcQueueFamilyIndex %d"
8071a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                    " or dstQueueFamilyIndex %d is greater than " PRINTF_SIZE_T_SPECIFIER
8072a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                    "queueFamilies crated for this device.",
8073a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                    funcName, reinterpret_cast<const uint64_t &>(mem_barrier->image), src_q_f_index, dst_q_f_index,
8074a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                    dev_data->phys_dev_properties.queue_family_properties.size());
80755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
80765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
80775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
80785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
80795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (mem_barrier) {
8080d678ec4f57d80aa89c24562e9ffe941d8d69e455Tony Barbour            if (mem_barrier->oldLayout != mem_barrier->newLayout) {
8081a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                skip |=
8082d678ec4f57d80aa89c24562e9ffe941d8d69e455Tony Barbour                    ValidateMaskBitsFromLayouts(dev_data, cmdBuffer, mem_barrier->srcAccessMask, mem_barrier->oldLayout, "Source");
8083a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                skip |=
8084d678ec4f57d80aa89c24562e9ffe941d8d69e455Tony Barbour                    ValidateMaskBitsFromLayouts(dev_data, cmdBuffer, mem_barrier->dstAccessMask, mem_barrier->newLayout, "Dest");
8085d678ec4f57d80aa89c24562e9ffe941d8d69e455Tony Barbour            }
80865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (mem_barrier->newLayout == VK_IMAGE_LAYOUT_UNDEFINED || mem_barrier->newLayout == VK_IMAGE_LAYOUT_PREINITIALIZED) {
8087a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8088cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                DRAWSTATE_INVALID_BARRIER, "DS",
8089cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                "%s: Image Layout cannot be transitioned to UNDEFINED or "
8090cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                "PREINITIALIZED.",
8091a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                funcName);
80925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
80931d5109d5e0dcc530b27e632e73e1be5e12a28dcdJamie Madill            VkFormat format = VK_FORMAT_UNDEFINED;
80941d5109d5e0dcc530b27e632e73e1be5e12a28dcdJamie Madill            uint32_t arrayLayers = 0, mipLevels = 0;
80955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            bool imageFound = false;
80966d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            if (image_data) {
80976d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis                format = image_data->createInfo.format;
80986d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis                arrayLayers = image_data->createInfo.arrayLayers;
80996d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis                mipLevels = image_data->createInfo.mipLevels;
81005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                imageFound = true;
81015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else if (dev_data->device_extensions.wsi_enabled) {
81029a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto imageswap_data = GetSwapchainFromImage(dev_data, mem_barrier->image);
8103170dc65b45f6bcdec47e02b3aa19435e55b32804Tobin Ehlis                if (imageswap_data) {
81049a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto swapchain_data = GetSwapchainNode(dev_data, imageswap_data);
8105b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis                    if (swapchain_data) {
8106b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis                        format = swapchain_data->createInfo.imageFormat;
8107b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis                        arrayLayers = swapchain_data->createInfo.imageArrayLayers;
81085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        mipLevels = 1;
81095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        imageFound = true;
81105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
81115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
81125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
81135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (imageFound) {
8114e08b485346524a30ddfe6526f7dcbbf78c776d10Mark Lobodzinski                skip |= ValidateImageSubrangeLevelLayerCounts(dev_data, mem_barrier->subresourceRange, funcName);
8115c37c65e9ff3a0abc86e706ee61d21e1dec882731Tobin Ehlis                auto aspect_mask = mem_barrier->subresourceRange.aspectMask;
8116a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                skip |= ValidateImageAspectMask(dev_data, image_data->image, format, aspect_mask, funcName);
8117f0d091deca3d4b90e1f31d75e062684dca160ad1Michael Lentine                int layerCount = (mem_barrier->subresourceRange.layerCount == VK_REMAINING_ARRAY_LAYERS)
8118f0d091deca3d4b90e1f31d75e062684dca160ad1Michael Lentine                                     ? 1
8119f0d091deca3d4b90e1f31d75e062684dca160ad1Michael Lentine                                     : mem_barrier->subresourceRange.layerCount;
8120f0d091deca3d4b90e1f31d75e062684dca160ad1Michael Lentine                if ((mem_barrier->subresourceRange.baseArrayLayer + layerCount) > arrayLayers) {
8121a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
8122cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    __LINE__, DRAWSTATE_INVALID_BARRIER, "DS",
8123cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    "%s: Subresource must have the sum of the "
8124cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    "baseArrayLayer (%d) and layerCount (%d) be less "
8125cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    "than or equal to the total number of layers (%d).",
8126a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                    funcName, mem_barrier->subresourceRange.baseArrayLayer,
8127a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                    mem_barrier->subresourceRange.layerCount, arrayLayers);
81285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
8129f0d091deca3d4b90e1f31d75e062684dca160ad1Michael Lentine                int levelCount = (mem_barrier->subresourceRange.levelCount == VK_REMAINING_MIP_LEVELS)
8130f0d091deca3d4b90e1f31d75e062684dca160ad1Michael Lentine                                     ? 1
8131f0d091deca3d4b90e1f31d75e062684dca160ad1Michael Lentine                                     : mem_barrier->subresourceRange.levelCount;
8132f0d091deca3d4b90e1f31d75e062684dca160ad1Michael Lentine                if ((mem_barrier->subresourceRange.baseMipLevel + levelCount) > mipLevels) {
8133cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
8134cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    __LINE__, DRAWSTATE_INVALID_BARRIER, "DS",
8135cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    "%s: Subresource must have the sum of the baseMipLevel "
8136cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    "(%d) and levelCount (%d) be less than or equal to "
8137cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    "the total number of levels (%d).",
8138cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    funcName, mem_barrier->subresourceRange.baseMipLevel, mem_barrier->subresourceRange.levelCount,
8139cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    mipLevels);
81405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
81415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
81425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
81435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
81445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < bufferBarrierCount; ++i) {
81455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto mem_barrier = &pBufferMemBarriers[i];
81465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (pCB->activeRenderPass) {
8147a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8148a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            DRAWSTATE_INVALID_BARRIER, "DS", "%s: Buffer Barriers cannot be used during a render pass.", funcName);
81495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8150cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!mem_barrier) continue;
81515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
81525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Validate buffer barrier queue family indices
81535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if ((mem_barrier->srcQueueFamilyIndex != VK_QUEUE_FAMILY_IGNORED &&
8154b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis             mem_barrier->srcQueueFamilyIndex >= dev_data->phys_dev_properties.queue_family_properties.size()) ||
81555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            (mem_barrier->dstQueueFamilyIndex != VK_QUEUE_FAMILY_IGNORED &&
8156b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis             mem_barrier->dstQueueFamilyIndex >= dev_data->phys_dev_properties.queue_family_properties.size())) {
8157a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8158a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            DRAWSTATE_INVALID_QUEUE_INDEX, "DS",
8159cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s: Buffer Barrier 0x%" PRIx64
8160cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            " has QueueFamilyIndex greater "
8161a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            "than the number of QueueFamilies (" PRINTF_SIZE_T_SPECIFIER ") for this device.",
8162a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            funcName, reinterpret_cast<const uint64_t &>(mem_barrier->buffer),
8163a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            dev_data->phys_dev_properties.queue_family_properties.size());
81645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
81655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
81669a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto buffer_state = GetBufferState(dev_data, mem_barrier->buffer);
81675cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        if (buffer_state) {
81685cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            auto buffer_size = buffer_state->requirements.size;
81695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (mem_barrier->offset >= buffer_size) {
8170a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8171a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                DRAWSTATE_INVALID_BARRIER, "DS", "%s: Buffer Barrier 0x%" PRIx64 " has offset 0x%" PRIx64
8172a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                                                 " which is not less than total size 0x%" PRIx64 ".",
8173a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                funcName, reinterpret_cast<const uint64_t &>(mem_barrier->buffer),
8174a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                reinterpret_cast<const uint64_t &>(mem_barrier->offset),
8175a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                reinterpret_cast<const uint64_t &>(buffer_size));
81765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else if (mem_barrier->size != VK_WHOLE_SIZE && (mem_barrier->offset + mem_barrier->size > buffer_size)) {
8177a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                skip |= log_msg(
817894c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8179414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                    DRAWSTATE_INVALID_BARRIER, "DS", "%s: Buffer Barrier 0x%" PRIx64 " has offset 0x%" PRIx64 " and size 0x%" PRIx64
8180414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                                                     " whose sum is greater than total size 0x%" PRIx64 ".",
818194c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis                    funcName, reinterpret_cast<const uint64_t &>(mem_barrier->buffer),
818294c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis                    reinterpret_cast<const uint64_t &>(mem_barrier->offset), reinterpret_cast<const uint64_t &>(mem_barrier->size),
818394c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis                    reinterpret_cast<const uint64_t &>(buffer_size));
81845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
81855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
81865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8187a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis    return skip;
81885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
81895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8190bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskibool validateEventStageMask(VkQueue queue, GLOBAL_CB_NODE *pCB, uint32_t eventCount, size_t firstEventIndex,
8191bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            VkPipelineStageFlags sourceStageMask) {
8192b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    bool skip_call = false;
8193b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    VkPipelineStageFlags stageMask = 0;
819456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
8195b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    for (uint32_t i = 0; i < eventCount; ++i) {
81962ab14387df9b890fe4b13494ea249dd03cf898d2Chris Forbes        auto event = pCB->events[firstEventIndex + i];
8197b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        auto queue_data = dev_data->queueMap.find(queue);
8198cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (queue_data == dev_data->queueMap.end()) return false;
81992ab14387df9b890fe4b13494ea249dd03cf898d2Chris Forbes        auto event_data = queue_data->second.eventToStageMap.find(event);
8200b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        if (event_data != queue_data->second.eventToStageMap.end()) {
8201b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            stageMask |= event_data->second;
8202b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        } else {
82039a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto global_event_data = GetEventNode(dev_data, event);
82049556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis            if (!global_event_data) {
8205b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT,
820627c3e0dda9e30d1d334728bbd373e8d7011257d4Chris Forbes                                     reinterpret_cast<const uint64_t &>(event), __LINE__, DRAWSTATE_INVALID_EVENT, "DS",
820727c3e0dda9e30d1d334728bbd373e8d7011257d4Chris Forbes                                     "Event 0x%" PRIx64 " cannot be waited on if it has never been set.",
82082ab14387df9b890fe4b13494ea249dd03cf898d2Chris Forbes                                     reinterpret_cast<const uint64_t &>(event));
8209b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            } else {
82109556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis                stageMask |= global_event_data->stageMask;
8211b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            }
8212b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        }
8213b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
8214c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    // TODO: Need to validate that host_bit is only set if set event is called
8215c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    // but set event can be called at any time.
8216c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    if (sourceStageMask != stageMask && sourceStageMask != (stageMask | VK_PIPELINE_STAGE_HOST_BIT)) {
8217c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8218cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             VALIDATION_ERROR_00254, "DS",
8219cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "Submitting cmdbuffer with call to VkCmdWaitEvents "
8220cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "using srcStageMask 0x%X which must be the bitwise "
8221cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "OR of the stageMask parameters used in calls to "
8222cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "vkCmdSetEvent and VK_PIPELINE_STAGE_HOST_BIT if "
8223cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "used with vkSetEvent but instead is 0x%X. %s",
82249bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             sourceStageMask, stageMask, validation_error_map[VALIDATION_ERROR_00254]);
8225b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
8226b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    return skip_call;
8227b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine}
8228b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine
822907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski// Note that we only check bits that HAVE required queueflags -- don't care entries are skipped
823007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinskistatic std::unordered_map<VkPipelineStageFlags, VkQueueFlags> supported_pipeline_stages_table = {
823107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT},
823207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT},
823307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_QUEUE_GRAPHICS_BIT},
823407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
823507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
823607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
823707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
823807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
823907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, VK_QUEUE_GRAPHICS_BIT},
824007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_QUEUE_GRAPHICS_BIT},
824107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_QUEUE_GRAPHICS_BIT},
824207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_QUEUE_COMPUTE_BIT},
824307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_TRANSFER_BIT, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT},
824407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_QUEUE_GRAPHICS_BIT}};
824507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
824607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinskistatic const VkPipelineStageFlags stage_flag_bit_array[] = {VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX,
824707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,
824807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
824907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
825007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT,
825107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT,
825207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT,
825307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
825407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
825507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
825607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
825707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
825807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_TRANSFER_BIT,
825907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT};
826007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
826107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinskibool CheckStageMaskQueueCompatibility(layer_data *dev_data, VkCommandBuffer command_buffer, VkPipelineStageFlags stage_mask,
826207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                      VkQueueFlags queue_flags, const char *function, const char *src_or_dest,
826307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                      UNIQUE_VALIDATION_ERROR_CODE error_code) {
826407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    bool skip = false;
826507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    // Lookup each bit in the stagemask and check for overlap between its table bits and queue_flags
826607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    for (const auto &item : stage_flag_bit_array) {
826707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        if (stage_mask & item) {
826807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski            if ((supported_pipeline_stages_table[item] & queue_flags) == 0) {
826907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                skip |=
827007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
827107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            reinterpret_cast<uint64_t &>(command_buffer), __LINE__, error_code, "DL",
827207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            "%s(): %s flag %s is not compatible with the queue family properties of this "
827307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            "command buffer. %s",
827407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            function, src_or_dest, string_VkPipelineStageFlagBits(static_cast<VkPipelineStageFlagBits>(item)),
827507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            validation_error_map[error_code]);
827607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski            }
827707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        }
827807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    }
827907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    return skip;
828007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski}
828107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
828207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinskibool ValidateStageMasksAgainstQueueCapabilities(layer_data *dev_data, GLOBAL_CB_NODE *cb_state,
828307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                VkPipelineStageFlags source_stage_mask, VkPipelineStageFlags dest_stage_mask,
828407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                const char *function, UNIQUE_VALIDATION_ERROR_CODE error_code) {
828507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    bool skip = false;
828607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    uint32_t queue_family_index = dev_data->commandPoolMap[cb_state->createInfo.commandPool].queueFamilyIndex;
828756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(dev_data->physical_device), instance_layer_data_map);
82889a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, dev_data->physical_device);
828907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
829007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    // Any pipeline stage included in srcStageMask or dstStageMask must be supported by the capabilities of the queue family
829107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    // specified by the queueFamilyIndex member of the VkCommandPoolCreateInfo structure that was used to create the VkCommandPool
829207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    // that commandBuffer was allocated from, as specified in the table of supported pipeline stages.
829307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
829407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    if (queue_family_index < physical_device_state->queue_family_properties.size()) {
829507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        VkQueueFlags specified_queue_flags = physical_device_state->queue_family_properties[queue_family_index].queueFlags;
829607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
829707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        if ((source_stage_mask & VK_PIPELINE_STAGE_ALL_COMMANDS_BIT) == 0) {
829807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski            skip |= CheckStageMaskQueueCompatibility(dev_data, cb_state->commandBuffer, source_stage_mask, specified_queue_flags,
829907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                     function, "srcStageMask", error_code);
830007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        }
830107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        if ((dest_stage_mask & VK_PIPELINE_STAGE_ALL_COMMANDS_BIT) == 0) {
830207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski            skip |= CheckStageMaskQueueCompatibility(dev_data, cb_state->commandBuffer, dest_stage_mask, specified_queue_flags,
830307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                     function, "dstStageMask", error_code);
830407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        }
830507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    }
830607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    return skip;
830707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski}
830807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
8309d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents,
8310d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                         VkPipelineStageFlags sourceStageMask, VkPipelineStageFlags dstStageMask,
8311d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                         uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
8312d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                         uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
8313d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                         uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
8314d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    bool skip = false;
831556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8316b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
83179a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
8318d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    if (cb_state) {
8319d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        skip |= ValidateStageMasksAgainstQueueCapabilities(dev_data, cb_state, sourceStageMask, dstStageMask, "vkCmdWaitEvents",
8320d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                                           VALIDATION_ERROR_02510);
8321208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip |= ValidateStageMaskGsTsEnables(dev_data, sourceStageMask, "vkCmdWaitEvents()", VALIDATION_ERROR_02067,
8322208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                                             VALIDATION_ERROR_02069);
8323208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip |= ValidateStageMaskGsTsEnables(dev_data, dstStageMask, "vkCmdWaitEvents()", VALIDATION_ERROR_02068,
8324208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                                             VALIDATION_ERROR_02070);
8325d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        auto first_event_index = cb_state->events.size();
83265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < eventCount; ++i) {
83279a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto event_state = GetEventNode(dev_data, pEvents[i]);
83284710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis            if (event_state) {
83294710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis                addCommandBufferBinding(&event_state->cb_bindings,
8330ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis                                        {reinterpret_cast<const uint64_t &>(pEvents[i]), VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT},
8331d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                        cb_state);
8332d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                event_state->cb_bindings.insert(cb_state);
8333ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis            }
8334d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski            cb_state->waitedEvents.insert(pEvents[i]);
8335d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski            cb_state->events.push_back(pEvents[i]);
83365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8337d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        std::function<bool(VkQueue)> event_update =
8338d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski            std::bind(validateEventStageMask, std::placeholders::_1, cb_state, eventCount, first_event_index, sourceStageMask);
8339d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        cb_state->eventUpdates.push_back(event_update);
8340d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        if (cb_state->state == CB_RECORDING) {
834129f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis            skip |= ValidateCmd(dev_data, cb_state, CMD_WAITEVENTS, "vkCmdWaitEvents()");
83421ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis            UpdateCmdBufferLastCmd(cb_state, CMD_WAITEVENTS);
83435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
8344d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski            skip |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdWaitEvents()");
83455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
834655867dbad6ae423b3bd78c15f6771031a710b5adMark Lobodzinski        skip |= TransitionImageLayouts(dev_data, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers);
8347364a03b109f0b2b37be2e13d293fa93b8af5203aMike Weiblen        skip |= ValidateBarriers("vkCmdWaitEvents()", commandBuffer, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
8348d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                 pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
83495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8350b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8351d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    if (!skip)
83524a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdWaitEvents(commandBuffer, eventCount, pEvents, sourceStageMask, dstStageMask,
83534a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                               memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers,
83544a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                               imageMemoryBarrierCount, pImageMemoryBarriers);
83555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
83565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8357d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask,
8358d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                              VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags,
8359d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                              uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
8360d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                              uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
8361d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                              uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
8362d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    bool skip = false;
836356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8364b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
83659a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
8366d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    if (cb_state) {
8367d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        skip |= ValidateStageMasksAgainstQueueCapabilities(dev_data, cb_state, srcStageMask, dstStageMask, "vkCmdPipelineBarrier",
8368d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                                           VALIDATION_ERROR_02513);
836929f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip |= ValidateCmd(dev_data, cb_state, CMD_PIPELINEBARRIER, "vkCmdPipelineBarrier()");
8370208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip |= ValidateStageMaskGsTsEnables(dev_data, srcStageMask, "vkCmdPipelineBarrier()", VALIDATION_ERROR_00265,
8371208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                                             VALIDATION_ERROR_00267);
8372208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip |= ValidateStageMaskGsTsEnables(dev_data, dstStageMask, "vkCmdPipelineBarrier()", VALIDATION_ERROR_00266,
8373208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                                             VALIDATION_ERROR_00268);
83741ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(cb_state, CMD_PIPELINEBARRIER);
837555867dbad6ae423b3bd78c15f6771031a710b5adMark Lobodzinski        skip |= TransitionImageLayouts(dev_data, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers);
8376364a03b109f0b2b37be2e13d293fa93b8af5203aMike Weiblen        skip |= ValidateBarriers("vkCmdPipelineBarrier()", commandBuffer, memoryBarrierCount, pMemoryBarriers,
8377d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                 bufferMemoryBarrierCount, pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
83785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8379b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8380d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    if (!skip)
83814a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, dependencyFlags, memoryBarrierCount,
83824a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                    pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers,
83834a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                    imageMemoryBarrierCount, pImageMemoryBarriers);
83845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
83855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8386d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentinebool setQueryState(VkQueue queue, VkCommandBuffer commandBuffer, QueryObject object, bool value) {
838756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
83889a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
8389d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    if (pCB) {
8390d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        pCB->queryToStateMap[object] = value;
8391d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    }
8392d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    auto queue_data = dev_data->queueMap.find(queue);
8393d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    if (queue_data != dev_data->queueMap.end()) {
8394d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        queue_data->second.queryToStateMap[object] = value;
8395d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    }
8396d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    return false;
8397d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine}
8398d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine
8399bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBeginQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot, VkFlags flags) {
840083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
840156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8402b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
84039a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
84045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
84055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        QueryObject query = {queryPool, slot};
84065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->activeQueries.insert(query);
84075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!pCB->startedQueries.count(query)) {
84085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pCB->startedQueries.insert(query);
84095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
841029f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_BEGINQUERY, "vkCmdBeginQuery()");
84111ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_BEGINQUERY);
84129a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        addCommandBufferBinding(&GetQueryPoolNode(dev_data, queryPool)->cb_bindings,
8413ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis                                {reinterpret_cast<uint64_t &>(queryPool), VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT}, pCB);
84145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8415b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8416cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdBeginQuery(commandBuffer, queryPool, slot, flags);
84175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
84185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
841989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdEndQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot) {
842083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
842156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8422b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
84239a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
84245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
84255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        QueryObject query = {queryPool, slot};
84265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!pCB->activeQueries.count(query)) {
842783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |=
84285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
84299bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        VALIDATION_ERROR_01041, "DS", "Ending a query before it was started: queryPool 0x%" PRIx64 ", index %d. %s",
84309bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        (uint64_t)(queryPool), slot, validation_error_map[VALIDATION_ERROR_01041]);
84315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
84325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pCB->activeQueries.erase(query);
84335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8434c2ec509029604290e981885108c06a9b7de565c1Karl Schultz        std::function<bool(VkQueue)> queryUpdate = std::bind(setQueryState, std::placeholders::_1, commandBuffer, query, true);
8435d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        pCB->queryUpdates.push_back(queryUpdate);
84365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (pCB->state == CB_RECORDING) {
843729f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis            skip_call |= ValidateCmd(dev_data, pCB, CMD_ENDQUERY, "VkCmdEndQuery()");
84381ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis            UpdateCmdBufferLastCmd(pCB, CMD_ENDQUERY);
84395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
844083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdEndQuery()");
84415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
84429a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        addCommandBufferBinding(&GetQueryPoolNode(dev_data, queryPool)->cb_bindings,
8443ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis                                {reinterpret_cast<uint64_t &>(queryPool), VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT}, pCB);
84445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8445b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8446cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdEndQuery(commandBuffer, queryPool, slot);
84475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
84485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8449bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdResetQueryPool(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery,
8450bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                             uint32_t queryCount) {
845183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
845256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8453b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
84549a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
84555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
84565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < queryCount; i++) {
84575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            QueryObject query = {queryPool, firstQuery + i};
84585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pCB->waitedEventsBeforeQueryReset[query] = pCB->waitedEvents;
8459c2ec509029604290e981885108c06a9b7de565c1Karl Schultz            std::function<bool(VkQueue)> queryUpdate = std::bind(setQueryState, std::placeholders::_1, commandBuffer, query, false);
8460d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            pCB->queryUpdates.push_back(queryUpdate);
84615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
84625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (pCB->state == CB_RECORDING) {
846329f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis            skip_call |= ValidateCmd(dev_data, pCB, CMD_RESETQUERYPOOL, "VkCmdResetQueryPool()");
84641ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis            UpdateCmdBufferLastCmd(pCB, CMD_RESETQUERYPOOL);
84655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
846683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdResetQueryPool()");
84675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8468ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen        skip_call |= insideRenderPass(dev_data, pCB, "vkCmdResetQueryPool()", VALIDATION_ERROR_01025);
84699a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        addCommandBufferBinding(&GetQueryPoolNode(dev_data, queryPool)->cb_bindings,
8470ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis                                {reinterpret_cast<uint64_t &>(queryPool), VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT}, pCB);
84715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8472b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8473cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdResetQueryPool(commandBuffer, queryPool, firstQuery, queryCount);
84745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
84755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8476d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentinebool validateQuery(VkQueue queue, GLOBAL_CB_NODE *pCB, VkQueryPool queryPool, uint32_t queryCount, uint32_t firstQuery) {
8477d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    bool skip_call = false;
847856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(pCB->commandBuffer), layer_data_map);
8479d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    auto queue_data = dev_data->queueMap.find(queue);
8480cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (queue_data == dev_data->queueMap.end()) return false;
8481d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    for (uint32_t i = 0; i < queryCount; i++) {
8482d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        QueryObject query = {queryPool, firstQuery + i};
8483d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        auto query_data = queue_data->second.queryToStateMap.find(query);
8484d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        bool fail = false;
8485d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        if (query_data != queue_data->second.queryToStateMap.end()) {
8486d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            if (!query_data->second) {
8487d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                fail = true;
8488d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            }
8489d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        } else {
8490d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            auto global_query_data = dev_data->queryToStateMap.find(query);
8491d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            if (global_query_data != dev_data->queryToStateMap.end()) {
8492d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                if (!global_query_data->second) {
8493d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                    fail = true;
8494d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                }
8495d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            } else {
8496d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                fail = true;
8497d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            }
8498d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        }
8499d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        if (fail) {
8500d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8501d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                                 DRAWSTATE_INVALID_QUERY, "DS",
8502d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                                 "Requesting a copy from query to buffer with invalid query: queryPool 0x%" PRIx64 ", index %d",
8503d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                                 reinterpret_cast<uint64_t &>(queryPool), firstQuery + i);
8504d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        }
8505d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    }
8506d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    return skip_call;
8507d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine}
8508d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine
8509bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdCopyQueryPoolResults(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery,
8510bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset,
8511bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   VkDeviceSize stride, VkQueryResultFlags flags) {
851283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
851356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8514b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
8515ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
85169a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
85179a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto dst_buff_state = GetBufferState(dev_data, dstBuffer);
85185cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (cb_node && dst_buff_state) {
851935ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis        skip_call |= ValidateMemoryIsBoundToBuffer(dev_data, dst_buff_state, "vkCmdCopyQueryPoolResults()", VALIDATION_ERROR_02526);
8520ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Update bindings between buffer and cmd buffer
85215cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        AddCommandBufferBindingBuffer(dev_data, cb_node, dst_buff_state);
8522ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Validate that DST buffer has correct usage flags set
85231b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes        skip_call |=
85245cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            ValidateBufferUsageFlags(dev_data, dst_buff_state, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, VALIDATION_ERROR_01066,
85251b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes                                     "vkCmdCopyQueryPoolResults()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
8526e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
85275cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            SetBufferMemoryValid(dev_data, dst_buff_state, true);
8528e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
85295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        };
85309f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
8531d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        std::function<bool(VkQueue)> queryUpdate =
8532ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis            std::bind(validateQuery, std::placeholders::_1, cb_node, queryPool, queryCount, firstQuery);
8533ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        cb_node->queryUpdates.push_back(queryUpdate);
8534ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        if (cb_node->state == CB_RECORDING) {
853529f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis            skip_call |= ValidateCmd(dev_data, cb_node, CMD_COPYQUERYPOOLRESULTS, "vkCmdCopyQueryPoolResults()");
85361ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis            UpdateCmdBufferLastCmd(cb_node, CMD_COPYQUERYPOOLRESULTS);
85375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
853883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdCopyQueryPoolResults()");
85395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8540ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen        skip_call |= insideRenderPass(dev_data, cb_node, "vkCmdCopyQueryPoolResults()", VALIDATION_ERROR_01074);
85419a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        addCommandBufferBinding(&GetQueryPoolNode(dev_data, queryPool)->cb_bindings,
8542ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis                                {reinterpret_cast<uint64_t &>(queryPool), VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT}, cb_node);
8543ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
8544ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
85455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8546b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
854783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (!skip_call)
85484a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdCopyQueryPoolResults(commandBuffer, queryPool, firstQuery, queryCount, dstBuffer, dstOffset,
85494a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                         stride, flags);
85505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
85515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8552bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdPushConstants(VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags,
8553bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                            uint32_t offset, uint32_t size, const void *pValues) {
855483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
855556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8556b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
85579a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
85585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
85595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (pCB->state == CB_RECORDING) {
856029f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis            skip_call |= ValidateCmd(dev_data, pCB, CMD_PUSHCONSTANTS, "vkCmdPushConstants()");
85611ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis            UpdateCmdBufferLastCmd(pCB, CMD_PUSHCONSTANTS);
85625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
856383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdPushConstants()");
85645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
85655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
856683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    skip_call |= validatePushConstantRange(dev_data, offset, size, "vkCmdPushConstants()");
85679e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    if (0 == stageFlags) {
856883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
85699bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             VALIDATION_ERROR_00996, "DS", "vkCmdPushConstants() call has no stageFlags set. %s",
85709bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             validation_error_map[VALIDATION_ERROR_00996]);
85719e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    }
85729e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz
8573a95cb74c9d0947ab3821b15e1289755286ea78eeKarl Schultz    // Check if push constant update is within any of the ranges with the same stage flags specified in pipeline layout.
8574c2a5a36d03bbe52f5854a5884346e4a84115e259Tobin Ehlis    auto pipeline_layout = getPipelineLayout(dev_data, layout);
857515a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis    // Coalesce adjacent/overlapping pipeline ranges before checking to see if incoming range is
857615a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis    // contained in the pipeline ranges.
857715a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis    // Build a {start, end} span list for ranges with matching stage flags.
857815a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis    const auto &ranges = pipeline_layout->push_constant_ranges;
857915a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis    struct span {
858015a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        uint32_t start;
858115a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        uint32_t end;
858215a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis    };
858315a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis    std::vector<span> spans;
858415a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis    spans.reserve(ranges.size());
858515a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis    for (const auto &iter : ranges) {
858615a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        if (iter.stageFlags == stageFlags) {
858715a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis            spans.push_back({iter.offset, iter.offset + iter.size});
858815a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        }
858915a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis    }
859015a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis    if (spans.size() == 0) {
859115a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        // There were no ranges that matched the stageFlags.
859215a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        skip_call |=
859315a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8594cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    VALIDATION_ERROR_00988, "DS", "vkCmdPushConstants() stageFlags = 0x%" PRIx32
8595cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                  " do not match "
85969bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                                  "the stageFlags in any of the ranges in pipeline layout 0x%" PRIx64 ". %s",
85979bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                    (uint32_t)stageFlags, (uint64_t)layout, validation_error_map[VALIDATION_ERROR_00988]);
85989e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    } else {
859915a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        // Sort span list by start value.
860015a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        struct comparer {
860115a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis            bool operator()(struct span i, struct span j) { return i.start < j.start; }
860215a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        } my_comparer;
860315a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        std::sort(spans.begin(), spans.end(), my_comparer);
860415a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis
860515a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        // Examine two spans at a time.
860615a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        std::vector<span>::iterator current = spans.begin();
860715a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        std::vector<span>::iterator next = current + 1;
860815a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        while (next != spans.end()) {
860915a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis            if (current->end < next->start) {
861015a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                // There is a gap; cannot coalesce. Move to the next two spans.
861115a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                ++current;
861215a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                ++next;
861315a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis            } else {
861415a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                // Coalesce the two spans.  The start of the next span
861515a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                // is within the current span, so pick the larger of
861615a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                // the end values to extend the current span.
861715a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                // Then delete the next span and set next to the span after it.
861815a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                current->end = max(current->end, next->end);
861915a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                next = spans.erase(next);
86209e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz            }
86219e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
8622a95cb74c9d0947ab3821b15e1289755286ea78eeKarl Schultz
862315a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        // Now we can check if the incoming range is within any of the spans.
862415a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        bool contained_in_a_range = false;
862515a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        for (uint32_t i = 0; i < spans.size(); ++i) {
862615a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis            if ((offset >= spans[i].start) && ((uint64_t)offset + (uint64_t)size <= (uint64_t)spans[i].end)) {
862715a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                contained_in_a_range = true;
862815a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                break;
8629a95cb74c9d0947ab3821b15e1289755286ea78eeKarl Schultz            }
86309e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
863115a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        if (!contained_in_a_range) {
8632cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8633cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 VALIDATION_ERROR_00988, "DS",
8634cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "vkCmdPushConstants() Push constant range [%d, %d) "
8635cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "with stageFlags = 0x%" PRIx32
8636cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 " "
8637cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "not within flag-matching ranges in pipeline layout 0x%" PRIx64 ". %s",
8638cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 offset, offset + size, (uint32_t)stageFlags, (uint64_t)layout,
8639cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 validation_error_map[VALIDATION_ERROR_00988]);
864015a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        }
86415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8642b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8643cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdPushConstants(commandBuffer, layout, stageFlags, offset, size, pValues);
86445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
86455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8646bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage,
8647bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                             VkQueryPool queryPool, uint32_t slot) {
864883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
864956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8650b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
86519a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
86525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
86535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        QueryObject query = {queryPool, slot};
8654c2ec509029604290e981885108c06a9b7de565c1Karl Schultz        std::function<bool(VkQueue)> queryUpdate = std::bind(setQueryState, std::placeholders::_1, commandBuffer, query, true);
8655d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        pCB->queryUpdates.push_back(queryUpdate);
86565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (pCB->state == CB_RECORDING) {
865729f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis            skip_call |= ValidateCmd(dev_data, pCB, CMD_WRITETIMESTAMP, "vkCmdWriteTimestamp()");
86581ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis            UpdateCmdBufferLastCmd(pCB, CMD_WRITETIMESTAMP);
86595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
866083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdWriteTimestamp()");
86615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
86625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8663b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8664cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdWriteTimestamp(commandBuffer, pipelineStage, queryPool, slot);
86655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
86665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
86676600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinskistatic bool MatchUsage(layer_data *dev_data, uint32_t count, const VkAttachmentReference *attachments,
86689bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                       const VkFramebufferCreateInfo *fbci, VkImageUsageFlagBits usage_flag,
86699bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                       UNIQUE_VALIDATION_ERROR_CODE error_code) {
86706600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    bool skip_call = false;
86716600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
86726600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    for (uint32_t attach = 0; attach < count; attach++) {
86736600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski        if (attachments[attach].attachment != VK_ATTACHMENT_UNUSED) {
86746600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            // Attachment counts are verified elsewhere, but prevent an invalid access
86756600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            if (attachments[attach].attachment < fbci->attachmentCount) {
86766600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                const VkImageView *image_view = &fbci->pAttachments[attachments[attach].attachment];
86779a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto view_state = GetImageViewState(dev_data, *image_view);
867879fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if (view_state) {
86799a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    const VkImageCreateInfo *ici = &GetImageState(dev_data, view_state->create_info.image)->createInfo;
86806600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                    if (ici != nullptr) {
86816600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                        if ((ici->usage & usage_flag) == 0) {
86826600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
86839bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                                 (VkDebugReportObjectTypeEXT)0, 0, __LINE__, error_code, "DS",
86846600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                                                 "vkCreateFramebuffer:  Framebuffer Attachment (%d) conflicts with the image's "
86859bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                                 "IMAGE_USAGE flags (%s). %s",
86869bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                                 attachments[attach].attachment, string_VkImageUsageFlagBits(usage_flag),
86879bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                                 validation_error_map[error_code]);
86886600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                        }
86896600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                    }
86906600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                }
86916600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            }
86926600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski        }
86936600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    }
86946600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    return skip_call;
86956600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski}
86966600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
8697d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis// Validate VkFramebufferCreateInfo which includes:
8698d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis// 1. attachmentCount equals renderPass attachmentCount
86995ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 2. corresponding framebuffer and renderpass attachments have matching formats
87005ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 3. corresponding framebuffer and renderpass attachments have matching sample counts
87015ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 4. fb attachments only have a single mip level
87025ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 5. fb attachment dimensions are each at least as large as the fb
87035ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 6. fb attachments use idenity swizzle
87045ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 7. fb attachments used by renderPass for color/input/ds have correct usage bit set
87056fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis// 8. fb dimensions are within physical device limits
8706d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlisstatic bool ValidateFramebufferCreateInfo(layer_data *dev_data, const VkFramebufferCreateInfo *pCreateInfo) {
87076600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    bool skip_call = false;
87086600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
87099a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto rp_state = GetRenderPassState(dev_data, pCreateInfo->renderPass);
8710127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis    if (rp_state) {
8711127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis        const VkRenderPassCreateInfo *rpci = rp_state->createInfo.ptr();
8712d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis        if (rpci->attachmentCount != pCreateInfo->attachmentCount) {
8713d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis            skip_call |= log_msg(
8714d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
87159bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                reinterpret_cast<const uint64_t &>(pCreateInfo->renderPass), __LINE__, VALIDATION_ERROR_00404, "DS",
8716d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis                "vkCreateFramebuffer(): VkFramebufferCreateInfo attachmentCount of %u does not match attachmentCount of %u of "
87179bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                "renderPass (0x%" PRIxLEAST64 ") being used to create Framebuffer. %s",
87189bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                pCreateInfo->attachmentCount, rpci->attachmentCount, reinterpret_cast<const uint64_t &>(pCreateInfo->renderPass),
87199bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                validation_error_map[VALIDATION_ERROR_00404]);
87205ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis        } else {
872141ebcb6b517b1de5ae456d46d866f5e84a96a2c5Tobin Ehlis            // attachmentCounts match, so make sure corresponding attachment details line up
87225ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis            const VkImageView *image_views = pCreateInfo->pAttachments;
87235ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis            for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
87249a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto view_state = GetImageViewState(dev_data, image_views[i]);
872512d5600c2f9e32343016fd944432ba95df370797Tobin Ehlis                auto &ivci = view_state->create_info;
872679fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if (ivci.format != rpci->pAttachments[i].format) {
87275ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                    skip_call |= log_msg(
87285ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
87299bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        reinterpret_cast<const uint64_t &>(pCreateInfo->renderPass), __LINE__, VALIDATION_ERROR_00408, "DS",
87309bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has format of %s that does not match "
87319bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "the format of "
87329bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "%s used by the corresponding attachment for renderPass (0x%" PRIxLEAST64 "). %s",
873379fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                        i, string_VkFormat(ivci.format), string_VkFormat(rpci->pAttachments[i].format),
87349bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        reinterpret_cast<const uint64_t &>(pCreateInfo->renderPass), validation_error_map[VALIDATION_ERROR_00408]);
87355ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
87369a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                const VkImageCreateInfo *ici = &GetImageState(dev_data, ivci.image)->createInfo;
87375ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                if (ici->samples != rpci->pAttachments[i].samples) {
873841ebcb6b517b1de5ae456d46d866f5e84a96a2c5Tobin Ehlis                    skip_call |= log_msg(
873941ebcb6b517b1de5ae456d46d866f5e84a96a2c5Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
87409bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        reinterpret_cast<const uint64_t &>(pCreateInfo->renderPass), __LINE__, VALIDATION_ERROR_00409, "DS",
87419bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has %s samples that do not match "
87429bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "the %s samples used by the corresponding attachment for renderPass (0x%" PRIxLEAST64 "). %s",
874341ebcb6b517b1de5ae456d46d866f5e84a96a2c5Tobin Ehlis                        i, string_VkSampleCountFlagBits(ici->samples), string_VkSampleCountFlagBits(rpci->pAttachments[i].samples),
87449bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        reinterpret_cast<const uint64_t &>(pCreateInfo->renderPass), validation_error_map[VALIDATION_ERROR_00409]);
87455ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
87465ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                // Verify that view only has a single mip level
874779fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if (ivci.subresourceRange.levelCount != 1) {
87489bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                    skip_call |=
87499bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
87509bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                VALIDATION_ERROR_00411, "DS",
87519bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has mip levelCount of %u "
87529bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                "but only a single mip level (levelCount ==  1) is allowed when creating a Framebuffer. %s",
87539bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                i, ivci.subresourceRange.levelCount, validation_error_map[VALIDATION_ERROR_00411]);
87545ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
875579fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                const uint32_t mip_level = ivci.subresourceRange.baseMipLevel;
8756aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                uint32_t mip_width = max(1u, ici->extent.width >> mip_level);
8757aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                uint32_t mip_height = max(1u, ici->extent.height >> mip_level);
875879fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if ((ivci.subresourceRange.layerCount < pCreateInfo->layers) || (mip_width < pCreateInfo->width) ||
8759aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                    (mip_height < pCreateInfo->height)) {
8760aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                    skip_call |=
87616fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
8762aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                DRAWSTATE_INVALID_FRAMEBUFFER_CREATE_INFO, "DS",
8763aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u mip level %u has dimensions smaller "
8764aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                "than the corresponding "
8765aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                "framebuffer dimensions. Attachment dimensions must be at least as large. Here are the respective "
8766aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                "dimensions for "
8767aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                "attachment #%u, framebuffer:\n"
8768aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                "width: %u, %u\n"
8769aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                "height: %u, %u\n"
8770aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                "layerCount: %u, %u\n",
877179fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                                i, ivci.subresourceRange.baseMipLevel, i, mip_width, pCreateInfo->width, mip_height,
877279fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                                pCreateInfo->height, ivci.subresourceRange.layerCount, pCreateInfo->layers);
87735ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
877479fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if (((ivci.components.r != VK_COMPONENT_SWIZZLE_IDENTITY) && (ivci.components.r != VK_COMPONENT_SWIZZLE_R)) ||
877579fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                    ((ivci.components.g != VK_COMPONENT_SWIZZLE_IDENTITY) && (ivci.components.g != VK_COMPONENT_SWIZZLE_G)) ||
877679fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                    ((ivci.components.b != VK_COMPONENT_SWIZZLE_IDENTITY) && (ivci.components.b != VK_COMPONENT_SWIZZLE_B)) ||
877779fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                    ((ivci.components.a != VK_COMPONENT_SWIZZLE_IDENTITY) && (ivci.components.a != VK_COMPONENT_SWIZZLE_A))) {
8778da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                    skip_call |= log_msg(
87796fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
87809bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        VALIDATION_ERROR_00412, "DS",
8781da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has non-identy swizzle. All framebuffer "
8782da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "attachments must have been created with the identity swizzle. Here are the actual swizzle values:\n"
8783da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "r swizzle = %s\n"
8784da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "g swizzle = %s\n"
8785da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "b swizzle = %s\n"
87869bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "a swizzle = %s\n"
87879bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "%s",
878879fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                        i, string_VkComponentSwizzle(ivci.components.r), string_VkComponentSwizzle(ivci.components.g),
87899bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        string_VkComponentSwizzle(ivci.components.b), string_VkComponentSwizzle(ivci.components.a),
87909bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        validation_error_map[VALIDATION_ERROR_00412]);
87915ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
87925ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis            }
8793d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis        }
87945ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis        // Verify correct attachment usage flags
87956600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski        for (uint32_t subpass = 0; subpass < rpci->subpassCount; subpass++) {
87966600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            // Verify input attachments:
87979bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt            skip_call |=
87989bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                MatchUsage(dev_data, rpci->pSubpasses[subpass].inputAttachmentCount, rpci->pSubpasses[subpass].pInputAttachments,
87999bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                           pCreateInfo, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, VALIDATION_ERROR_00407);
88006600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            // Verify color attachments:
88019bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt            skip_call |=
88029bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                MatchUsage(dev_data, rpci->pSubpasses[subpass].colorAttachmentCount, rpci->pSubpasses[subpass].pColorAttachments,
88039bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                           pCreateInfo, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VALIDATION_ERROR_00405);
88046600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            // Verify depth/stencil attachments:
88056600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            if (rpci->pSubpasses[subpass].pDepthStencilAttachment != nullptr) {
88066600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                skip_call |= MatchUsage(dev_data, 1, rpci->pSubpasses[subpass].pDepthStencilAttachment, pCreateInfo,
88079bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                        VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VALIDATION_ERROR_00406);
88086600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            }
88096600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski        }
88106600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    }
88116fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis    // Verify FB dimensions are within physical device limits
88129bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    if (pCreateInfo->width > dev_data->phys_dev_properties.properties.limits.maxFramebufferWidth) {
88136fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
88149bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             VALIDATION_ERROR_00413, "DS",
88159bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo width exceeds physical device limits. "
88169bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "Requested width: %u, device max: %u\n"
88179bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "%s",
88186fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis                             pCreateInfo->width, dev_data->phys_dev_properties.properties.limits.maxFramebufferWidth,
88199bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             validation_error_map[VALIDATION_ERROR_00413]);
88209bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    }
88219bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    if (pCreateInfo->height > dev_data->phys_dev_properties.properties.limits.maxFramebufferHeight) {
88229bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
88239bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             VALIDATION_ERROR_00414, "DS",
88249bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo height exceeds physical device limits. "
88259bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "Requested height: %u, device max: %u\n"
88269bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "%s",
88276fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis                             pCreateInfo->height, dev_data->phys_dev_properties.properties.limits.maxFramebufferHeight,
88289bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             validation_error_map[VALIDATION_ERROR_00414]);
88299bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    }
88309bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    if (pCreateInfo->layers > dev_data->phys_dev_properties.properties.limits.maxFramebufferLayers) {
88319bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
88329bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             VALIDATION_ERROR_00415, "DS",
88339bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo layers exceeds physical device limits. "
88349bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "Requested layers: %u, device max: %u\n"
88359bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "%s",
88369bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             pCreateInfo->layers, dev_data->phys_dev_properties.properties.limits.maxFramebufferLayers,
88379bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             validation_error_map[VALIDATION_ERROR_00415]);
88386fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis    }
88396600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    return skip_call;
88406600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski}
88416600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
884264c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis// Validate VkFramebufferCreateInfo state prior to calling down chain to create Framebuffer object
884364c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis//  Return true if an error is encountered and callback returns true to skip call down chain
884464c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis//   false indicates that call down chain should proceed
884564c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlisstatic bool PreCallValidateCreateFramebuffer(layer_data *dev_data, const VkFramebufferCreateInfo *pCreateInfo) {
884664c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    // TODO : Verify that renderPass FB is created with is compatible with FB
884764c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    bool skip_call = false;
8848d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis    skip_call |= ValidateFramebufferCreateInfo(dev_data, pCreateInfo);
884964c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    return skip_call;
885064c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis}
885164c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis
885254e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis// CreateFramebuffer state has been validated and call down chain completed so record new framebuffer object
885354e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlisstatic void PostCallRecordCreateFramebuffer(layer_data *dev_data, const VkFramebufferCreateInfo *pCreateInfo, VkFramebuffer fb) {
885454e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis    // Shadow create info and store in map
8855c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    std::unique_ptr<FRAMEBUFFER_STATE> fb_state(
8856c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis        new FRAMEBUFFER_STATE(fb, pCreateInfo, dev_data->renderPassMap[pCreateInfo->renderPass]->createInfo.ptr()));
885776f04ca0e692f9f15d5ef7e0c658c24d11f34ebcTobin Ehlis
885854e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
885954e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        VkImageView view = pCreateInfo->pAttachments[i];
88609a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto view_state = GetImageViewState(dev_data, view);
886179fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis        if (!view_state) {
886254e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis            continue;
886354e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        }
886454e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        MT_FB_ATTACHMENT_INFO fb_info;
88659a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        fb_info.mem = GetImageState(dev_data, view_state->create_info.image)->binding.mem;
8866883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        fb_info.view_state = view_state;
886779fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis        fb_info.image = view_state->create_info.image;
8868c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis        fb_state->attachments.push_back(fb_info);
886954e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis    }
8870c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    dev_data->frameBufferMap[fb] = std::move(fb_state);
887154e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis}
887254e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis
887389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateFramebuffer(VkDevice device, const VkFramebufferCreateInfo *pCreateInfo,
8874bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkAllocationCallbacks *pAllocator, VkFramebuffer *pFramebuffer) {
887556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
887664c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
887764c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    bool skip_call = PreCallValidateCreateFramebuffer(dev_data, pCreateInfo);
887864c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    lock.unlock();
887964c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis
8880cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
888164c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis
88824a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateFramebuffer(device, pCreateInfo, pAllocator, pFramebuffer);
88836600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
88845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
888564c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis        lock.lock();
888654e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        PostCallRecordCreateFramebuffer(dev_data, pCreateInfo, *pFramebuffer);
888754e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        lock.unlock();
88885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
88895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
88905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
88915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8892e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool FindDependency(const int index, const int dependent, const std::vector<DAGNode> &subpass_to_node,
8893e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                           std::unordered_set<uint32_t> &processed_nodes) {
88945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If we have already checked this node we have not found a dependency path so return false.
8895cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (processed_nodes.count(index)) return false;
88965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    processed_nodes.insert(index);
88975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    const DAGNode &node = subpass_to_node[index];
88985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Look for a dependency path. If one exists return true else recurse on the previous nodes.
8899593f84b63934f07483e5e5a20fd352df8ab4f8c9Bruce Dawson    if (std::find(node.prev.begin(), node.prev.end(), static_cast<uint32_t>(dependent)) == node.prev.end()) {
89005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto elem : node.prev) {
8901cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (FindDependency(elem, dependent, subpass_to_node, processed_nodes)) return true;
89025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
89035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
8904e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        return true;
89055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8906e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    return false;
89075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
89085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
89098860b85a52096f9f9b28616bc37feed505497a54Chris Forbesstatic bool CheckDependencyExists(const layer_data *dev_data, const int subpass, const std::vector<uint32_t> &dependent_subpasses,
8910e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                                  const std::vector<DAGNode> &subpass_to_node, bool &skip_call) {
8911e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool result = true;
89125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Loop through all subpasses that share the same attachment and make sure a dependency exists
89135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t k = 0; k < dependent_subpasses.size(); ++k) {
8914cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (static_cast<uint32_t>(subpass) == dependent_subpasses[k]) continue;
89155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const DAGNode &node = subpass_to_node[subpass];
89165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Check for a specified dependency between the two nodes. If one exists we are done.
89175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto prev_elem = std::find(node.prev.begin(), node.prev.end(), dependent_subpasses[k]);
89185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto next_elem = std::find(node.next.begin(), node.next.end(), dependent_subpasses[k]);
89195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (prev_elem == node.prev.end() && next_elem == node.next.end()) {
89207655cb8b5eb52badee0b011729a05afa36316d69Jan-Harald Fredriksen            // If no dependency exits an implicit dependency still might. If not, throw an error.
89215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            std::unordered_set<uint32_t> processed_nodes;
89227655cb8b5eb52badee0b011729a05afa36316d69Jan-Harald Fredriksen            if (!(FindDependency(subpass, dependent_subpasses[k], subpass_to_node, processed_nodes) ||
8923bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                  FindDependency(dependent_subpasses[k], subpass, subpass_to_node, processed_nodes))) {
89248860b85a52096f9f9b28616bc37feed505497a54Chris Forbes                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
89255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                     __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
89265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                     "A dependency between subpasses %d and %d must exist but one is not specified.", subpass,
89275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                     dependent_subpasses[k]);
8928e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                result = false;
89295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
89305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
89315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
89325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
89335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
89345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
89358860b85a52096f9f9b28616bc37feed505497a54Chris Forbesstatic bool CheckPreserved(const layer_data *dev_data, const VkRenderPassCreateInfo *pCreateInfo, const int index,
8936e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                           const uint32_t attachment, const std::vector<DAGNode> &subpass_to_node, int depth, bool &skip_call) {
89375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    const DAGNode &node = subpass_to_node[index];
89385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If this node writes to the attachment return true as next nodes need to preserve the attachment.
89395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[index];
89405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
8941cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (attachment == subpass.pColorAttachments[j].attachment) return true;
89425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8943a4ea781e8fff70c9db0bedad7fcb6bba08e35da7Tony Barbour    for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
8944a4ea781e8fff70c9db0bedad7fcb6bba08e35da7Tony Barbour        if (attachment == subpass.pInputAttachments[j].attachment) return true;
8945a4ea781e8fff70c9db0bedad7fcb6bba08e35da7Tony Barbour    }
89465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
8947cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (attachment == subpass.pDepthStencilAttachment->attachment) return true;
89485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8949e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool result = false;
89505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Loop through previous nodes and see if any of them write to the attachment.
89515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto elem : node.prev) {
89528860b85a52096f9f9b28616bc37feed505497a54Chris Forbes        result |= CheckPreserved(dev_data, pCreateInfo, elem, attachment, subpass_to_node, depth + 1, skip_call);
89535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
89545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If the attachment was written to by a previous node than this node needs to preserve it.
89555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result && depth > 0) {
8956e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        bool has_preserved = false;
89575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.preserveAttachmentCount; ++j) {
89585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (subpass.pPreserveAttachments[j] == attachment) {
8959e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                has_preserved = true;
89605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                break;
89615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
89625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8963e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        if (!has_preserved) {
89645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            skip_call |=
89658860b85a52096f9f9b28616bc37feed505497a54Chris Forbes                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
89665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        DRAWSTATE_INVALID_RENDERPASS, "DS",
89675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        "Attachment %d is used by a later subpass and must be preserved in subpass %d.", attachment, index);
89685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
89695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
89705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
89715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
89725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8973cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskitemplate <class T>
8974cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskibool isRangeOverlapping(T offset1, T size1, T offset2, T size2) {
89755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return (((offset1 + size1) > offset2) && ((offset1 + size1) < (offset2 + size2))) ||
89765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis           ((offset1 > offset2) && (offset1 < (offset2 + size2)));
89775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
89785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
89795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisbool isRegionOverlapping(VkImageSubresourceRange range1, VkImageSubresourceRange range2) {
89805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return (isRangeOverlapping(range1.baseMipLevel, range1.levelCount, range2.baseMipLevel, range2.levelCount) &&
89815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            isRangeOverlapping(range1.baseArrayLayer, range1.layerCount, range2.baseArrayLayer, range2.layerCount));
89825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
89835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8984c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlisstatic bool ValidateDependencies(const layer_data *dev_data, FRAMEBUFFER_STATE const *framebuffer,
8985127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                                 RENDER_PASS_STATE const *renderPass) {
8986e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
8987fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    auto const pFramebufferInfo = framebuffer->createInfo.ptr();
8988fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    auto const pCreateInfo = renderPass->createInfo.ptr();
8989bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto const &subpass_to_node = renderPass->subpassToNode;
89905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<std::vector<uint32_t>> output_attachment_to_subpass(pCreateInfo->attachmentCount);
89915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<std::vector<uint32_t>> input_attachment_to_subpass(pCreateInfo->attachmentCount);
89925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<std::vector<uint32_t>> overlapping_attachments(pCreateInfo->attachmentCount);
89935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Find overlapping attachments
89945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
89955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = i + 1; j < pCreateInfo->attachmentCount; ++j) {
89965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            VkImageView viewi = pFramebufferInfo->pAttachments[i];
89975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            VkImageView viewj = pFramebufferInfo->pAttachments[j];
89985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (viewi == viewj) {
89995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[i].push_back(j);
90005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[j].push_back(i);
90015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                continue;
90025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
90039a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto view_state_i = GetImageViewState(dev_data, viewi);
90049a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto view_state_j = GetImageViewState(dev_data, viewj);
900579fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis            if (!view_state_i || !view_state_j) {
90065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                continue;
90075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
900879fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis            auto view_ci_i = view_state_i->create_info;
900979fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis            auto view_ci_j = view_state_j->create_info;
901079fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis            if (view_ci_i.image == view_ci_j.image && isRegionOverlapping(view_ci_i.subresourceRange, view_ci_j.subresourceRange)) {
90115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[i].push_back(j);
90125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[j].push_back(i);
90135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                continue;
90145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
90159a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto image_data_i = GetImageState(dev_data, view_ci_i.image);
90169a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto image_data_j = GetImageState(dev_data, view_ci_j.image);
90176d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            if (!image_data_i || !image_data_j) {
90185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                continue;
90195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
9020e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis            if (image_data_i->binding.mem == image_data_j->binding.mem &&
9021e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis                isRangeOverlapping(image_data_i->binding.offset, image_data_i->binding.size, image_data_j->binding.offset,
9022e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis                                   image_data_j->binding.size)) {
90235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[i].push_back(j);
90245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[j].push_back(i);
90255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
90265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
90275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
90285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < overlapping_attachments.size(); ++i) {
90295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t attachment = i;
90305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto other_attachment : overlapping_attachments[i]) {
90315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!(pCreateInfo->pAttachments[attachment].flags & VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT)) {
90329bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
9033cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     __LINE__, VALIDATION_ERROR_00324, "DS",
9034cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "Attachment %d aliases attachment %d but doesn't "
9035cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "set VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT. %s",
90369bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                     attachment, other_attachment, validation_error_map[VALIDATION_ERROR_00324]);
90375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
90385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!(pCreateInfo->pAttachments[other_attachment].flags & VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT)) {
90399bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
9040cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     __LINE__, VALIDATION_ERROR_00324, "DS",
9041cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "Attachment %d aliases attachment %d but doesn't "
9042cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "set VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT. %s",
90439bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                     other_attachment, attachment, validation_error_map[VALIDATION_ERROR_00324]);
90445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
90455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
90465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
90475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Find for each attachment the subpasses that use them.
90481c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young    unordered_set<uint32_t> attachmentIndices;
90495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
90505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
90511c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young        attachmentIndices.clear();
90525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
90535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t attachment = subpass.pInputAttachments[j].attachment;
9054cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) continue;
90555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            input_attachment_to_subpass[attachment].push_back(i);
90565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            for (auto overlapping_attachment : overlapping_attachments[attachment]) {
90575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                input_attachment_to_subpass[overlapping_attachment].push_back(i);
90585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
90595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
90605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
90615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t attachment = subpass.pColorAttachments[j].attachment;
9062cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) continue;
90635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            output_attachment_to_subpass[attachment].push_back(i);
90645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            for (auto overlapping_attachment : overlapping_attachments[attachment]) {
90655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                output_attachment_to_subpass[overlapping_attachment].push_back(i);
90665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
90671c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young            attachmentIndices.insert(attachment);
90685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
90695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
90705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t attachment = subpass.pDepthStencilAttachment->attachment;
90715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            output_attachment_to_subpass[attachment].push_back(i);
90725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            for (auto overlapping_attachment : overlapping_attachments[attachment]) {
90735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                output_attachment_to_subpass[overlapping_attachment].push_back(i);
90745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
90751c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young
90761c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young            if (attachmentIndices.count(attachment)) {
90771c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young                skip_call |=
90788860b85a52096f9f9b28616bc37feed505497a54Chris Forbes                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
90798860b85a52096f9f9b28616bc37feed505497a54Chris Forbes                            DRAWSTATE_INVALID_RENDERPASS, "DS",
90808860b85a52096f9f9b28616bc37feed505497a54Chris Forbes                            "Cannot use same attachment (%u) as both color and depth output in same subpass (%u).", attachment, i);
90811c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young            }
90825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
90835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
90845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If there is a dependency needed make sure one exists
90855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
90865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
90875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // If the attachment is an input then all subpasses that output must have a dependency relationship
90885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
908993fe72ec8460857bdb3c101095e6eb96d6171341Chris Forbes            uint32_t attachment = subpass.pInputAttachments[j].attachment;
9090cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) continue;
90918860b85a52096f9f9b28616bc37feed505497a54Chris Forbes            CheckDependencyExists(dev_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip_call);
90925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
90935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // If the attachment is an output then all subpasses that use the attachment must have a dependency relationship
90945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
909593fe72ec8460857bdb3c101095e6eb96d6171341Chris Forbes            uint32_t attachment = subpass.pColorAttachments[j].attachment;
9096cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) continue;
90978860b85a52096f9f9b28616bc37feed505497a54Chris Forbes            CheckDependencyExists(dev_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip_call);
90988860b85a52096f9f9b28616bc37feed505497a54Chris Forbes            CheckDependencyExists(dev_data, i, input_attachment_to_subpass[attachment], subpass_to_node, skip_call);
90995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
91005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
91015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            const uint32_t &attachment = subpass.pDepthStencilAttachment->attachment;
91028860b85a52096f9f9b28616bc37feed505497a54Chris Forbes            CheckDependencyExists(dev_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip_call);
91038860b85a52096f9f9b28616bc37feed505497a54Chris Forbes            CheckDependencyExists(dev_data, i, input_attachment_to_subpass[attachment], subpass_to_node, skip_call);
91045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
91055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
91065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Loop through implicit dependencies, if this pass reads make sure the attachment is preserved for all passes after it was
91075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // written.
91085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
91095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
91105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
91118860b85a52096f9f9b28616bc37feed505497a54Chris Forbes            CheckPreserved(dev_data, pCreateInfo, i, subpass.pInputAttachments[j].attachment, subpass_to_node, 0, skip_call);
91125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
91135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
91145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
91155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
91165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
91178860b85a52096f9f9b28616bc37feed505497a54Chris Forbesstatic bool CreatePassDAG(const layer_data *dev_data, VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
9118e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                          std::vector<DAGNode> &subpass_to_node, std::vector<bool> &has_self_dependency) {
9119e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
91205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
91215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        DAGNode &subpass_node = subpass_to_node[i];
91225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        subpass_node.pass = i;
91235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
91245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->dependencyCount; ++i) {
91255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubpassDependency &dependency = pCreateInfo->pDependencies[i];
912666a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes        if (dependency.srcSubpass == VK_SUBPASS_EXTERNAL || dependency.dstSubpass == VK_SUBPASS_EXTERNAL) {
912766a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes            if (dependency.srcSubpass == dependency.dstSubpass) {
912866a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes                skip_call |=
91298860b85a52096f9f9b28616bc37feed505497a54Chris Forbes                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
913066a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes                            DRAWSTATE_INVALID_RENDERPASS, "DS", "The src and dest subpasses cannot both be external.");
913166a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes            }
913266a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes        } else if (dependency.srcSubpass > dependency.dstSubpass) {
91338860b85a52096f9f9b28616bc37feed505497a54Chris Forbes            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
91345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                 DRAWSTATE_INVALID_RENDERPASS, "DS",
91355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                 "Depedency graph must be specified such that an earlier pass cannot depend on a later pass.");
91365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (dependency.srcSubpass == dependency.dstSubpass) {
91375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            has_self_dependency[dependency.srcSubpass] = true;
91385c6aacf95832467d52b2fde1130b04bef559573aChris Forbes        } else {
91395c6aacf95832467d52b2fde1130b04bef559573aChris Forbes            subpass_to_node[dependency.dstSubpass].prev.push_back(dependency.srcSubpass);
91405c6aacf95832467d52b2fde1130b04bef559573aChris Forbes            subpass_to_node[dependency.srcSubpass].next.push_back(dependency.dstSubpass);
91415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
91425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
91435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
91445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
9145918c283ac4f8c604b79abd0c8b5706d2a7352a34Chris Forbes
914689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo,
9147bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                  const VkAllocationCallbacks *pAllocator, VkShaderModule *pShaderModule) {
914856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
9149e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
9150c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski    spv_result_t spv_valid = SPV_SUCCESS;
9151b1f65702539fd041337fccd493dc6d38dd2a603eChris Forbes
9152e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski    if (!GetDisables(dev_data)->shader_validation) {
9153e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski        // Use SPIRV-Tools validator to try and catch any issues with the module itself
9154e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski        spv_context ctx = spvContextCreate(SPV_ENV_VULKAN_1_0);
9155e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski        spv_const_binary_t binary{pCreateInfo->pCode, pCreateInfo->codeSize / sizeof(uint32_t)};
9156e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski        spv_diagnostic diag = nullptr;
9157b1f65702539fd041337fccd493dc6d38dd2a603eChris Forbes
9158c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski        spv_valid = spvValidate(ctx, &binary, &diag);
9159c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski        if (spv_valid != SPV_SUCCESS) {
91605581a92674a04d2ef49fde417e657f64e3aeed69Mark Lobodzinski            if (!dev_data->device_extensions.nv_glsl_shader_enabled || (pCreateInfo->pCode[0] == spv::MagicNumber)) {
9161c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski                skip_call |= log_msg(dev_data->report_data,
9162c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski                    spv_valid == SPV_WARNING ? VK_DEBUG_REPORT_WARNING_BIT_EXT : VK_DEBUG_REPORT_ERROR_BIT_EXT,
9163c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski                    VkDebugReportObjectTypeEXT(0), 0, __LINE__, SHADER_CHECKER_INCONSISTENT_SPIRV, "SC",
9164c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski                    "SPIR-V module not valid: %s", diag && diag->error ? diag->error : "(no error text)");
9165c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski            }
9166e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski        }
91675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9168e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski        spvDiagnosticDestroy(diag);
9169e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski        spvContextDestroy(ctx);
9170b1f65702539fd041337fccd493dc6d38dd2a603eChris Forbes
9171e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski        if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
9172e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski    }
91735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
91744a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult res = dev_data->dispatch_table.CreateShaderModule(device, pCreateInfo, pAllocator, pShaderModule);
91755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9176e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski    if (res == VK_SUCCESS && !GetDisables(dev_data)->shader_validation) {
9177b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
9178c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski        const auto new_shader_module = (SPV_SUCCESS == spv_valid ? new shader_module(pCreateInfo) : new shader_module());
9179c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski        dev_data->shaderModuleMap[*pShaderModule] = unique_ptr<shader_module>(new_shader_module);
91805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
91815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return res;
91825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
91835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
91844f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinskistatic bool ValidateAttachmentIndex(layer_data *dev_data, uint32_t attachment, uint32_t attachment_count, const char *type) {
91854f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    bool skip_call = false;
91864f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    if (attachment >= attachment_count && attachment != VK_ATTACHMENT_UNUSED) {
91874f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9188e52ca7be57745459d6aa4903a3880fc8eaa9d3dcChris Forbes                             VALIDATION_ERROR_00325, "DS",
9189bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             "CreateRenderPass: %s attachment %d must be less than the total number of attachments %d. %s", type,
9190bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             attachment, attachment_count, validation_error_map[VALIDATION_ERROR_00325]);
91914f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    }
91924f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    return skip_call;
91934f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski}
91944f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
9195bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool IsPowerOfTwo(unsigned x) { return x && !(x & (x - 1)); }
9196805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
91974f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinskistatic bool ValidateRenderpassAttachmentUsage(layer_data *dev_data, const VkRenderPassCreateInfo *pCreateInfo) {
91984f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    bool skip_call = false;
91994f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
92004f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
92014f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        if (subpass.pipelineBindPoint != VK_PIPELINE_BIND_POINT_GRAPHICS) {
92029bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
92039bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                 VALIDATION_ERROR_00347, "DS",
92049bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                 "CreateRenderPass: Pipeline bind point for subpass %d must be VK_PIPELINE_BIND_POINT_GRAPHICS. %s",
92059bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                 i, validation_error_map[VALIDATION_ERROR_00347]);
92064f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
92074f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        for (uint32_t j = 0; j < subpass.preserveAttachmentCount; ++j) {
92084f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            uint32_t attachment = subpass.pPreserveAttachments[j];
92094f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) {
92104f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
92119bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                     __LINE__, VALIDATION_ERROR_00356, "DS",
92129bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                     "CreateRenderPass:  Preserve attachment (%d) must not be VK_ATTACHMENT_UNUSED. %s", j,
92139bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                     validation_error_map[VALIDATION_ERROR_00356]);
92144f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            } else {
92154f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                skip_call |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Preserve");
92164f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            }
92174f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
92186a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes
9219bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto subpass_performs_resolve =
9220bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            subpass.pResolveAttachments &&
9221bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            std::any_of(subpass.pResolveAttachments, subpass.pResolveAttachments + subpass.colorAttachmentCount,
9222bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        [](VkAttachmentReference ref) { return ref.attachment != VK_ATTACHMENT_UNUSED; });
92236a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes
9224805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes        unsigned sample_count = 0;
9225805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
92264f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
92274f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            uint32_t attachment;
92284f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            if (subpass.pResolveAttachments) {
92294f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                attachment = subpass.pResolveAttachments[j].attachment;
92304f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                skip_call |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Resolve");
92316a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes
92326a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes                if (!skip_call && attachment != VK_ATTACHMENT_UNUSED &&
92336a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes                    pCreateInfo->pAttachments[attachment].samples != VK_SAMPLE_COUNT_1_BIT) {
92346a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
92359bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         __LINE__, VALIDATION_ERROR_00352, "DS",
92366a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes                                         "CreateRenderPass:  Subpass %u requests multisample resolve into attachment %u, "
92379bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         "which must have VK_SAMPLE_COUNT_1_BIT but has %s. %s",
92389bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         i, attachment, string_VkSampleCountFlagBits(pCreateInfo->pAttachments[attachment].samples),
92399bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         validation_error_map[VALIDATION_ERROR_00352]);
92406a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes                }
92414f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            }
92424f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            attachment = subpass.pColorAttachments[j].attachment;
92434f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            skip_call |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Color");
92446a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes
9245805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes            if (!skip_call && attachment != VK_ATTACHMENT_UNUSED) {
9246805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes                sample_count |= (unsigned)pCreateInfo->pAttachments[attachment].samples;
9247805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
9248bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (subpass_performs_resolve && pCreateInfo->pAttachments[attachment].samples == VK_SAMPLE_COUNT_1_BIT) {
9249dc7c45f01ae5690f7c969b4760463c1a6bac52d5Chris Forbes                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
92509bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         __LINE__, VALIDATION_ERROR_00351, "DS",
9251dc7c45f01ae5690f7c969b4760463c1a6bac52d5Chris Forbes                                         "CreateRenderPass:  Subpass %u requests multisample resolve from attachment %u "
92529bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         "which has VK_SAMPLE_COUNT_1_BIT. %s",
92539bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         i, attachment, validation_error_map[VALIDATION_ERROR_00351]);
9254dc7c45f01ae5690f7c969b4760463c1a6bac52d5Chris Forbes                }
92556a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes            }
92564f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
9257dc7c45f01ae5690f7c969b4760463c1a6bac52d5Chris Forbes
92584f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
92594f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            uint32_t attachment = subpass.pDepthStencilAttachment->attachment;
92604f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            skip_call |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Depth stencil");
9261805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
9262805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes            if (!skip_call && attachment != VK_ATTACHMENT_UNUSED) {
9263805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes                sample_count |= (unsigned)pCreateInfo->pAttachments[attachment].samples;
9264805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes            }
92654f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
9266dc7c45f01ae5690f7c969b4760463c1a6bac52d5Chris Forbes
92674f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
92684f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            uint32_t attachment = subpass.pInputAttachments[j].attachment;
92694f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            skip_call |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Input");
92704f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
9271805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
9272805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes        if (sample_count && !IsPowerOfTwo(sample_count)) {
92739bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
9274cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 VALIDATION_ERROR_00337, "DS",
9275cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "CreateRenderPass:  Subpass %u attempts to render to "
9276cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "attachments with inconsistent sample counts. %s",
92779bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                 i, validation_error_map[VALIDATION_ERROR_00337]);
9278805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes        }
92794f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    }
92804f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    return skip_call;
92814f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski}
92824f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
928389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
92844f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                                                const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) {
9285e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
928656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
92874f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
92884f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    std::unique_lock<std::mutex> lock(global_lock);
92894f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    // TODO: As part of wrapping up the mem_tracker/core_validation merge the following routine should be consolidated with
92904f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    //       ValidateLayouts.
92914f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    skip_call |= ValidateRenderpassAttachmentUsage(dev_data, pCreateInfo);
9292208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->dependencyCount; ++i) {
9293208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip_call |= ValidateStageMaskGsTsEnables(dev_data, pCreateInfo->pDependencies[i].srcStageMask, "vkCreateRenderPass()",
9294208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                                                  VALIDATION_ERROR_00368, VALIDATION_ERROR_00370);
9295208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip_call |= ValidateStageMaskGsTsEnables(dev_data, pCreateInfo->pDependencies[i].dstStageMask, "vkCreateRenderPass()",
9296208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                                                  VALIDATION_ERROR_00369, VALIDATION_ERROR_00371);
9297208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    }
9298ab38df28c5ae1816c5fa33c0c7840c6950e83f0dChris Forbes    if (!skip_call) {
9299ab38df28c5ae1816c5fa33c0c7840c6950e83f0dChris Forbes        skip_call |= ValidateLayouts(dev_data, device, pCreateInfo);
9300ab38df28c5ae1816c5fa33c0c7840c6950e83f0dChris Forbes    }
9301ff6101de02d1677fb54962e2ff57875e76898e26Chris Forbes    lock.unlock();
93024f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
93034f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    if (skip_call) {
93044f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        return VK_ERROR_VALIDATION_FAILED_EXT;
93054f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    }
93064f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
93074a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateRenderPass(device, pCreateInfo, pAllocator, pRenderPass);
9308ff6101de02d1677fb54962e2ff57875e76898e26Chris Forbes
93095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
93104f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        lock.lock();
93114f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
93124f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        std::vector<bool> has_self_dependency(pCreateInfo->subpassCount);
93134f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        std::vector<DAGNode> subpass_to_node(pCreateInfo->subpassCount);
93144f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        skip_call |= CreatePassDAG(dev_data, device, pCreateInfo, subpass_to_node, has_self_dependency);
93154f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
9316127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis        auto render_pass = unique_ptr<RENDER_PASS_STATE>(new RENDER_PASS_STATE(pCreateInfo));
931798cddf7090b5d5dcc382045867753ef703d1c3d3Chris Forbes        render_pass->renderPass = *pRenderPass;
9318cf2686cdbb12af8a29ca598c126b5e37215f0ef7Chris Forbes        render_pass->hasSelfDependency = has_self_dependency;
9319cf2686cdbb12af8a29ca598c126b5e37215f0ef7Chris Forbes        render_pass->subpassToNode = subpass_to_node;
9320db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes
932187e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis        // TODO: Maybe fill list and then copy instead of locking
9322cf2686cdbb12af8a29ca598c126b5e37215f0ef7Chris Forbes        std::unordered_map<uint32_t, bool> &attachment_first_read = render_pass->attachment_first_read;
93236600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski        std::unordered_map<uint32_t, VkImageLayout> &attachment_first_layout = render_pass->attachment_first_layout;
932487e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis        for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
932587e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis            const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
932687e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis            for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
93274f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                uint32_t attachment = subpass.pColorAttachments[j].attachment;
93284f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                if (!attachment_first_read.count(attachment)) {
93294f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                    attachment_first_read.insert(std::make_pair(attachment, false));
93304f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                    attachment_first_layout.insert(std::make_pair(attachment, subpass.pColorAttachments[j].layout));
93310d615f0a5724edac98475366cf3e486dccc1f2d6Michael Lentine                }
933287e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis            }
933387e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis            if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
933487e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis                uint32_t attachment = subpass.pDepthStencilAttachment->attachment;
93354f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                if (!attachment_first_read.count(attachment)) {
93364f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                    attachment_first_read.insert(std::make_pair(attachment, false));
93374f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                    attachment_first_layout.insert(std::make_pair(attachment, subpass.pDepthStencilAttachment->layout));
933824991fb692f7e2d457da50d50c40f2705591300cMichael Lentine                }
933987e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis            }
9340a5ce96d7c88653668a2b33a6b72bd3cb16d73f48Michael Lentine            for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
9341a5ce96d7c88653668a2b33a6b72bd3cb16d73f48Michael Lentine                uint32_t attachment = subpass.pInputAttachments[j].attachment;
93424f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                if (!attachment_first_read.count(attachment)) {
93434f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                    attachment_first_read.insert(std::make_pair(attachment, true));
93444f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                    attachment_first_layout.insert(std::make_pair(attachment, subpass.pInputAttachments[j].layout));
934524991fb692f7e2d457da50d50c40f2705591300cMichael Lentine                }
9346a5ce96d7c88653668a2b33a6b72bd3cb16d73f48Michael Lentine            }
934787e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis        }
9348db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes
9349fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes        dev_data->renderPassMap[*pRenderPass] = std::move(render_pass);
93505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
93515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
93525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
93534f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
93549bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardtstatic bool validatePrimaryCommandBuffer(const layer_data *dev_data, const GLOBAL_CB_NODE *pCB, const std::string &cmd_name,
93559bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         UNIQUE_VALIDATION_ERROR_CODE error_code) {
9356e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
93575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
93588860b85a52096f9f9b28616bc37feed505497a54Chris Forbes        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
93599bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             error_code, "DS", "Cannot execute command %s on a secondary command buffer. %s", cmd_name.c_str(),
93609bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             validation_error_map[error_code]);
93615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
93625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
93635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
93645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
93658860b85a52096f9f9b28616bc37feed505497a54Chris Forbesstatic bool VerifyRenderAreaBounds(const layer_data *dev_data, const VkRenderPassBeginInfo *pRenderPassBegin) {
9366885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine    bool skip_call = false;
9367c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    const safe_VkFramebufferCreateInfo *pFramebufferInfo =
93689a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        &GetFramebufferState(dev_data, pRenderPassBegin->framebuffer)->createInfo;
9369885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine    if (pRenderPassBegin->renderArea.offset.x < 0 ||
9370885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine        (pRenderPassBegin->renderArea.offset.x + pRenderPassBegin->renderArea.extent.width) > pFramebufferInfo->width ||
9371885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine        pRenderPassBegin->renderArea.offset.y < 0 ||
9372885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine        (pRenderPassBegin->renderArea.offset.y + pRenderPassBegin->renderArea.extent.height) > pFramebufferInfo->height) {
9373885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine        skip_call |= static_cast<bool>(log_msg(
93748860b85a52096f9f9b28616bc37feed505497a54Chris Forbes            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9375885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            DRAWSTATE_INVALID_RENDER_AREA, "CORE",
9376885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            "Cannot execute a render pass with renderArea not within the bound of the "
9377885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            "framebuffer. RenderArea: x %d, y %d, width %d, height %d. Framebuffer: width %d, "
9378885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            "height %d.",
9379885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            pRenderPassBegin->renderArea.offset.x, pRenderPassBegin->renderArea.offset.y, pRenderPassBegin->renderArea.extent.width,
9380885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            pRenderPassBegin->renderArea.extent.height, pFramebufferInfo->width, pFramebufferInfo->height));
9381885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine    }
9382885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine    return skip_call;
9383885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine}
9384885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine
93851a65650f856376768d7b03ea2d080aaff87cacfdMark 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
93861a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski// [load|store]Op flag must be checked
93871a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski// TODO: The memory valid flag in DEVICE_MEM_INFO should probably be split to track the validity of stencil memory separately.
9388cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskitemplate <typename T>
9389cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskistatic bool FormatSpecificLoadAndStoreOpSettings(VkFormat format, T color_depth_op, T stencil_op, T op) {
9390a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski    if (color_depth_op != op && stencil_op != op) {
9391a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski        return false;
9392a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski    }
93931a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski    bool check_color_depth_load_op = !vk_format_is_stencil_only(format);
93941a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski    bool check_stencil_load_op = vk_format_is_depth_and_stencil(format) || !check_color_depth_load_op;
9395a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski
9396a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski    return (((check_color_depth_load_op == true) && (color_depth_op == op)) ||
9397a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski            ((check_stencil_load_op == true) && (stencil_op == op)));
93981a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski}
93991a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski
9400bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
9401bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              VkSubpassContents contents) {
940283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
940356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
9404b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
94059a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *cb_node = GetCBNode(dev_data, commandBuffer);
94069a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto render_pass_state = pRenderPassBegin ? GetRenderPassState(dev_data, pRenderPassBegin->renderPass) : nullptr;
94079a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto framebuffer = pRenderPassBegin ? GetFramebufferState(dev_data, pRenderPassBegin->framebuffer) : nullptr;
9408f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis    if (cb_node) {
9409308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski        if (render_pass_state) {
9410cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            uint32_t clear_op_size = 0;  // Make sure pClearValues is at least as large as last LOAD_OP_CLEAR
9411f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->activeFramebuffer = pRenderPassBegin->framebuffer;
9412308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski            for (uint32_t i = 0; i < render_pass_state->createInfo.attachmentCount; ++i) {
9413f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes                MT_FB_ATTACHMENT_INFO &fb_info = framebuffer->attachments[i];
9414308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski                auto pAttachment = &render_pass_state->createInfo.pAttachments[i];
9415bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->loadOp, pAttachment->stencilLoadOp,
94161a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski                                                         VK_ATTACHMENT_LOAD_OP_CLEAR)) {
941792bc0680357019834b7529148ab6d73353ce02c7Mark Lobodzinski                    clear_op_size = static_cast<uint32_t>(i) + 1;
941816387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    std::function<bool()> function = [=]() {
94199a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        SetImageMemoryValid(dev_data, GetImageState(dev_data, fb_info.image), true);
942016387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                        return false;
942116387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    };
9422f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                    cb_node->validate_functions.push_back(function);
9423db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes                } else if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->loadOp,
9424bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                pAttachment->stencilLoadOp, VK_ATTACHMENT_LOAD_OP_DONT_CARE)) {
942516387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    std::function<bool()> function = [=]() {
94269a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        SetImageMemoryValid(dev_data, GetImageState(dev_data, fb_info.image), false);
942716387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                        return false;
942816387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    };
9429f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                    cb_node->validate_functions.push_back(function);
9430db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes                } else if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->loadOp,
9431bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                pAttachment->stencilLoadOp, VK_ATTACHMENT_LOAD_OP_LOAD)) {
943216387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    std::function<bool()> function = [=]() {
94339a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        return ValidateImageMemoryIsValid(dev_data, GetImageState(dev_data, fb_info.image),
9434f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis                                                          "vkCmdBeginRenderPass()");
943516387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    };
9436f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                    cb_node->validate_functions.push_back(function);
943716387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                }
9438308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski                if (render_pass_state->attachment_first_read[i]) {
943916387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    std::function<bool()> function = [=]() {
94409a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        return ValidateImageMemoryIsValid(dev_data, GetImageState(dev_data, fb_info.image),
9441f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis                                                          "vkCmdBeginRenderPass()");
944216387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    };
9443f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                    cb_node->validate_functions.push_back(function);
94445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
94455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
94466de3c6ffa0819ee37cd5cecee918b062145e2ff1Tobin Ehlis            if (clear_op_size > pRenderPassBegin->clearValueCount) {
9447369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                skip_call |= log_msg(
9448369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
9449308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski                    reinterpret_cast<uint64_t &>(render_pass_state->renderPass), __LINE__, VALIDATION_ERROR_00442, "DS",
9450bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "In vkCmdBeginRenderPass() the VkRenderPassBeginInfo struct has a clearValueCount of %u but there must "
9451bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "be at least %u entries in pClearValues array to account for the highest index attachment in renderPass "
9452cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "0x%" PRIx64
9453cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    " that uses VK_ATTACHMENT_LOAD_OP_CLEAR is %u. Note that the pClearValues array "
9454bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "is indexed by attachment number so even if some pClearValues entries between 0 and %u correspond to "
9455bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "attachments that aren't cleared they will be ignored. %s",
9456308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski                    pRenderPassBegin->clearValueCount, clear_op_size, reinterpret_cast<uint64_t &>(render_pass_state->renderPass),
94575504d0369cbc97ad7c221eddbad439bfb83e3fb6Mark Lobodzinski                    clear_op_size, clear_op_size - 1, validation_error_map[VALIDATION_ERROR_00442]);
9458369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan            }
9459369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan            if (clear_op_size < pRenderPassBegin->clearValueCount) {
9460369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                skip_call |= log_msg(
9461369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                    dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
9462308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski                    reinterpret_cast<uint64_t &>(render_pass_state->renderPass), __LINE__,
9463308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski                    DRAWSTATE_RENDERPASS_TOO_MANY_CLEAR_VALUES, "DS",
9464369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                    "In vkCmdBeginRenderPass() the VkRenderPassBeginInfo struct has a clearValueCount of %u but only first %u "
94657bab3d8f0599701f6e26a2d76314588486ae99c9Mark Lobodzinski                    "entries in pClearValues array are used. The highest index of any attachment in renderPass 0x%" PRIx64
9466369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                    " that uses VK_ATTACHMENT_LOAD_OP_CLEAR is %u - other pClearValues are ignored.",
9467308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski                    pRenderPassBegin->clearValueCount, clear_op_size, reinterpret_cast<uint64_t &>(render_pass_state->renderPass),
94687bab3d8f0599701f6e26a2d76314588486ae99c9Mark Lobodzinski                    clear_op_size - 1);
94693d71bca42a843966040d6ada9c029e0ec9f35ca6Tobin Ehlis            }
947083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= VerifyRenderAreaBounds(dev_data, pRenderPassBegin);
947155867dbad6ae423b3bd78c15f6771031a710b5adMark Lobodzinski            skip_call |= VerifyFramebufferAndRenderPassLayouts(dev_data, cb_node, pRenderPassBegin,
94729a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                                                               GetFramebufferState(dev_data, pRenderPassBegin->framebuffer));
9473ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen            skip_call |= insideRenderPass(dev_data, cb_node, "vkCmdBeginRenderPass()", VALIDATION_ERROR_00440);
9474308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski            skip_call |= ValidateDependencies(dev_data, framebuffer, render_pass_state);
94759bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt            skip_call |= validatePrimaryCommandBuffer(dev_data, cb_node, "vkCmdBeginRenderPass", VALIDATION_ERROR_00441);
947629f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis            skip_call |= ValidateCmd(dev_data, cb_node, CMD_BEGINRENDERPASS, "vkCmdBeginRenderPass()");
94771ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis            UpdateCmdBufferLastCmd(cb_node, CMD_BEGINRENDERPASS);
9478308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski            cb_node->activeRenderPass = render_pass_state;
94795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // This is a shallow copy as that is all that is needed for now
9480f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->activeRenderPassBeginInfo = *pRenderPassBegin;
9481f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->activeSubpass = 0;
9482f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->activeSubpassContents = contents;
9483f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->framebuffers.insert(pRenderPassBegin->framebuffer);
9484883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis            // Connect this framebuffer and its children to this cmdBuffer
9485883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis            AddFramebufferBinding(dev_data, cb_node, framebuffer);
9486ea0f86230ff5c52f805ac831a1ed5a92bd123368Chris Forbes            // transition attachments to the correct layouts for the first subpass
948755867dbad6ae423b3bd78c15f6771031a710b5adMark Lobodzinski            TransitionSubpassLayouts(dev_data, cb_node, &cb_node->activeRenderPassBeginInfo, cb_node->activeSubpass, framebuffer);
94885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
94895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9490b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
949183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (!skip_call) {
94924a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdBeginRenderPass(commandBuffer, pRenderPassBegin, contents);
94935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
94945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
94955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
949689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents) {
949783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
949856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
9499b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
95009a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
95015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
95029bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt        skip_call |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdNextSubpass", VALIDATION_ERROR_00459);
950329f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_NEXTSUBPASS, "vkCmdNextSubpass()");
95041ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_NEXTSUBPASS);
9505ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen        skip_call |= outsideRenderPass(dev_data, pCB, "vkCmdNextSubpass()", VALIDATION_ERROR_00458);
950680281691386b37385846f21b38e8c9d4b12cc74eChris Forbes
9507fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes        auto subpassCount = pCB->activeRenderPass->createInfo.subpassCount;
950880281691386b37385846f21b38e8c9d4b12cc74eChris Forbes        if (pCB->activeSubpass == subpassCount - 1) {
95099bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt            skip_call |= log_msg(
95109bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
95119bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                reinterpret_cast<uint64_t>(commandBuffer), __LINE__, VALIDATION_ERROR_00453, "DS",
95129bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                "vkCmdNextSubpass(): Attempted to advance beyond final subpass. %s", validation_error_map[VALIDATION_ERROR_00453]);
951380281691386b37385846f21b38e8c9d4b12cc74eChris Forbes        }
95145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9515b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
951696ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes
9517cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return;
951896ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes
95194a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.CmdNextSubpass(commandBuffer, contents);
952096ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes
952196ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes    if (pCB) {
9522bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        lock.lock();
9523bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pCB->activeSubpass++;
9524bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pCB->activeSubpassContents = contents;
952555867dbad6ae423b3bd78c15f6771031a710b5adMark Lobodzinski        TransitionSubpassLayouts(dev_data, pCB, &pCB->activeRenderPassBeginInfo, pCB->activeSubpass,
95269a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                                 GetFramebufferState(dev_data, pCB->activeRenderPassBeginInfo.framebuffer));
952796ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes    }
95285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
95295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
953089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdEndRenderPass(VkCommandBuffer commandBuffer) {
953183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
953256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
9533b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
95349a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pCB = GetCBNode(dev_data, commandBuffer);
953555867dbad6ae423b3bd78c15f6771031a710b5adMark Lobodzinski    FRAMEBUFFER_STATE *framebuffer = NULL;
953658c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes    if (pCB) {
9537127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis        RENDER_PASS_STATE *rp_state = pCB->activeRenderPass;
95389a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        framebuffer = GetFramebufferState(dev_data, pCB->activeFramebuffer);
9539127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis        if (rp_state) {
9540127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis            if (pCB->activeSubpass != rp_state->createInfo.subpassCount - 1) {
95419bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                skip_call |= log_msg(
95429bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
95439bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                    reinterpret_cast<uint64_t>(commandBuffer), __LINE__, VALIDATION_ERROR_00460, "DS",
95449bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                    "vkCmdEndRenderPass(): Called before reaching final subpass. %s", validation_error_map[VALIDATION_ERROR_00460]);
954502a3382f28fc7c6ec6018165be88aa6fc4f05c9eChris Forbes            }
954602a3382f28fc7c6ec6018165be88aa6fc4f05c9eChris Forbes
9547127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis            for (size_t i = 0; i < rp_state->createInfo.attachmentCount; ++i) {
9548e3ad4b1284408353cc56a04951c1df1f35a636ceChris Forbes                MT_FB_ATTACHMENT_INFO &fb_info = framebuffer->attachments[i];
9549127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                auto pAttachment = &rp_state->createInfo.pAttachments[i];
9550bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->storeOp, pAttachment->stencilStoreOp,
9551bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                         VK_ATTACHMENT_STORE_OP_STORE)) {
955258c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    std::function<bool()> function = [=]() {
95539a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        SetImageMemoryValid(dev_data, GetImageState(dev_data, fb_info.image), true);
955458c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                        return false;
955558c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    };
955658c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    pCB->validate_functions.push_back(function);
9557db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes                } else if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->storeOp,
9558bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                pAttachment->stencilStoreOp, VK_ATTACHMENT_STORE_OP_DONT_CARE)) {
955958c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    std::function<bool()> function = [=]() {
95609a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        SetImageMemoryValid(dev_data, GetImageState(dev_data, fb_info.image), false);
956158c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                        return false;
956258c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    };
956358c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    pCB->validate_functions.push_back(function);
95645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
95655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
95665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
9567ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen        skip_call |= outsideRenderPass(dev_data, pCB, "vkCmdEndRenderpass()", VALIDATION_ERROR_00464);
95689bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt        skip_call |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdEndRenderPass", VALIDATION_ERROR_00465);
956929f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_ENDRENDERPASS, "vkCmdEndRenderPass()");
95701ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_ENDRENDERPASS);
95710e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes    }
95720e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes    lock.unlock();
95730e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes
9574cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return;
95750e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes
95764a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.CmdEndRenderPass(commandBuffer);
95770e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes
95780e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes    if (pCB) {
95790e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes        lock.lock();
958055867dbad6ae423b3bd78c15f6771031a710b5adMark Lobodzinski        TransitionFinalSubpassLayouts(dev_data, pCB, &pCB->activeRenderPassBeginInfo, framebuffer);
958158c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes        pCB->activeRenderPass = nullptr;
958258c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes        pCB->activeSubpass = 0;
958358c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes        pCB->activeFramebuffer = VK_NULL_HANDLE;
95845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
95855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
95865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9587a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlisstatic bool logInvalidAttachmentMessage(layer_data *dev_data, VkCommandBuffer secondaryBuffer, uint32_t primaryAttach,
9588a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                        uint32_t secondaryAttach, const char *msg) {
95895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9590cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                   VALIDATION_ERROR_02059, "DS", "vkCmdExecuteCommands() called w/ invalid Secondary Cmd Buffer 0x%" PRIx64
9591cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                 " which has a render pass "
9592cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                 "that is not compatible with the Primary Cmd Buffer current render pass. "
9593cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                 "Attachment %u is not compatible with %u: %s. %s",
95949bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                   reinterpret_cast<uint64_t &>(secondaryBuffer), primaryAttach, secondaryAttach, msg,
95959bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                   validation_error_map[VALIDATION_ERROR_02059]);
95965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
95975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9598a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlisstatic bool validateAttachmentCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer,
9599a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                            VkRenderPassCreateInfo const *primaryPassCI, uint32_t primaryAttach,
9600a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                            VkCommandBuffer secondaryBuffer, VkRenderPassCreateInfo const *secondaryPassCI,
9601e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                                            uint32_t secondaryAttach, bool is_multi) {
96025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool skip_call = false;
9603a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (primaryPassCI->attachmentCount <= primaryAttach) {
96045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        primaryAttach = VK_ATTACHMENT_UNUSED;
96055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9606a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (secondaryPassCI->attachmentCount <= secondaryAttach) {
96075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        secondaryAttach = VK_ATTACHMENT_UNUSED;
96085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
96095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (primaryAttach == VK_ATTACHMENT_UNUSED && secondaryAttach == VK_ATTACHMENT_UNUSED) {
96105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return skip_call;
96115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
96125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (primaryAttach == VK_ATTACHMENT_UNUSED) {
9613a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach,
9614a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                                 "The first is unused while the second is not.");
96155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return skip_call;
96165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
96175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (secondaryAttach == VK_ATTACHMENT_UNUSED) {
9618a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach,
9619a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                                 "The second is unused while the first is not.");
96205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return skip_call;
96215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9622a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (primaryPassCI->pAttachments[primaryAttach].format != secondaryPassCI->pAttachments[secondaryAttach].format) {
9623a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        skip_call |=
9624a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis            logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach, "They have different formats.");
96255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9626a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (primaryPassCI->pAttachments[primaryAttach].samples != secondaryPassCI->pAttachments[secondaryAttach].samples) {
9627a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        skip_call |=
9628a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis            logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach, "They have different samples.");
96295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9630a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (is_multi && primaryPassCI->pAttachments[primaryAttach].flags != secondaryPassCI->pAttachments[secondaryAttach].flags) {
9631a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        skip_call |=
9632a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis            logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach, "They have different flags.");
96335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
96345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
96355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
96365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9637a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlisstatic bool validateSubpassCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer,
9638a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                         VkRenderPassCreateInfo const *primaryPassCI, VkCommandBuffer secondaryBuffer,
9639a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                         VkRenderPassCreateInfo const *secondaryPassCI, const int subpass, bool is_multi) {
96405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool skip_call = false;
9641a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    const VkSubpassDescription &primary_desc = primaryPassCI->pSubpasses[subpass];
9642a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    const VkSubpassDescription &secondary_desc = secondaryPassCI->pSubpasses[subpass];
96435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t maxInputAttachmentCount = std::max(primary_desc.inputAttachmentCount, secondary_desc.inputAttachmentCount);
96445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < maxInputAttachmentCount; ++i) {
96455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primary_input_attach = VK_ATTACHMENT_UNUSED, secondary_input_attach = VK_ATTACHMENT_UNUSED;
96465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < primary_desc.inputAttachmentCount) {
96475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            primary_input_attach = primary_desc.pInputAttachments[i].attachment;
96485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
96495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < secondary_desc.inputAttachmentCount) {
96505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            secondary_input_attach = secondary_desc.pInputAttachments[i].attachment;
96515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
9652a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPassCI, primary_input_attach, secondaryBuffer,
9653a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                                     secondaryPassCI, secondary_input_attach, is_multi);
96545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
96555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t maxColorAttachmentCount = std::max(primary_desc.colorAttachmentCount, secondary_desc.colorAttachmentCount);
96565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < maxColorAttachmentCount; ++i) {
96575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primary_color_attach = VK_ATTACHMENT_UNUSED, secondary_color_attach = VK_ATTACHMENT_UNUSED;
96585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < primary_desc.colorAttachmentCount) {
96595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            primary_color_attach = primary_desc.pColorAttachments[i].attachment;
96605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
96615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < secondary_desc.colorAttachmentCount) {
96625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            secondary_color_attach = secondary_desc.pColorAttachments[i].attachment;
96635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
9664a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPassCI, primary_color_attach, secondaryBuffer,
9665a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                                     secondaryPassCI, secondary_color_attach, is_multi);
96665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primary_resolve_attach = VK_ATTACHMENT_UNUSED, secondary_resolve_attach = VK_ATTACHMENT_UNUSED;
96675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < primary_desc.colorAttachmentCount && primary_desc.pResolveAttachments) {
96685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            primary_resolve_attach = primary_desc.pResolveAttachments[i].attachment;
96695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
96705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < secondary_desc.colorAttachmentCount && secondary_desc.pResolveAttachments) {
96715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            secondary_resolve_attach = secondary_desc.pResolveAttachments[i].attachment;
96725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
9673a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPassCI, primary_resolve_attach,
9674a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                                     secondaryBuffer, secondaryPassCI, secondary_resolve_attach, is_multi);
96755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
96765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t primary_depthstencil_attach = VK_ATTACHMENT_UNUSED, secondary_depthstencil_attach = VK_ATTACHMENT_UNUSED;
96775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (primary_desc.pDepthStencilAttachment) {
96785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        primary_depthstencil_attach = primary_desc.pDepthStencilAttachment[0].attachment;
96795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
96805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (secondary_desc.pDepthStencilAttachment) {
96815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        secondary_depthstencil_attach = secondary_desc.pDepthStencilAttachment[0].attachment;
96825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9683a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPassCI, primary_depthstencil_attach,
9684a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                                 secondaryBuffer, secondaryPassCI, secondary_depthstencil_attach, is_multi);
96855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
96865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
96875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9688a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis// Verify that given renderPass CreateInfo for primary and secondary command buffers are compatible.
9689a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis//  This function deals directly with the CreateInfo, there are overloaded versions below that can take the renderPass handle and
9690a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis//  will then feed into this function
9691a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlisstatic bool validateRenderPassCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer,
9692a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                            VkRenderPassCreateInfo const *primaryPassCI, VkCommandBuffer secondaryBuffer,
9693a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                            VkRenderPassCreateInfo const *secondaryPassCI) {
96945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool skip_call = false;
9695a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis
9696a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (primaryPassCI->subpassCount != secondaryPassCI->subpassCount) {
96975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
96985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                             DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
9699a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                             "vkCmdExecuteCommands() called w/ invalid secondary Cmd Buffer 0x%" PRIx64
9700a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                             " that has a subpassCount of %u that is incompatible with the primary Cmd Buffer 0x%" PRIx64
9701a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                             " that has a subpassCount of %u.",
9702a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                             reinterpret_cast<uint64_t &>(secondaryBuffer), secondaryPassCI->subpassCount,
9703a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                             reinterpret_cast<uint64_t &>(primaryBuffer), primaryPassCI->subpassCount);
9704a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    } else {
9705a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        for (uint32_t i = 0; i < primaryPassCI->subpassCount; ++i) {
9706a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis            skip_call |= validateSubpassCompatibility(dev_data, primaryBuffer, primaryPassCI, secondaryBuffer, secondaryPassCI, i,
9707a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                                      primaryPassCI->subpassCount > 1);
9708a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        }
97095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
97105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
97115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
97125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9713e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool validateFramebuffer(layer_data *dev_data, VkCommandBuffer primaryBuffer, const GLOBAL_CB_NODE *pCB,
9714e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                                VkCommandBuffer secondaryBuffer, const GLOBAL_CB_NODE *pSubCB) {
97155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool skip_call = false;
97165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (!pSubCB->beginInfo.pInheritanceInfo) {
97175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return skip_call;
97185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9719c5b97dda856ff837638b3ebb7e231d5507c495a3Chris Forbes    VkFramebuffer primary_fb = pCB->activeFramebuffer;
97205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkFramebuffer secondary_fb = pSubCB->beginInfo.pInheritanceInfo->framebuffer;
97215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (secondary_fb != VK_NULL_HANDLE) {
97225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (primary_fb != secondary_fb) {
97239bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt            skip_call |= log_msg(
97249bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
97259bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                VALIDATION_ERROR_02060, "DS",
97269bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                "vkCmdExecuteCommands() called w/ invalid secondary command buffer 0x%" PRIx64 " which has a framebuffer 0x%" PRIx64
97279bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                " that is not the same as the primary command buffer's current active framebuffer 0x%" PRIx64 ". %s",
97289bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                reinterpret_cast<uint64_t &>(secondaryBuffer), reinterpret_cast<uint64_t &>(secondary_fb),
97299bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                reinterpret_cast<uint64_t &>(primary_fb), validation_error_map[VALIDATION_ERROR_02060]);
97305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
97319a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto fb = GetFramebufferState(dev_data, secondary_fb);
9732e3ad4b1284408353cc56a04951c1df1f35a636ceChris Forbes        if (!fb) {
9733bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9734bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
9735bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 "vkCmdExecuteCommands() called w/ invalid Cmd Buffer 0x%p "
9736bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 "which has invalid framebuffer 0x%" PRIx64 ".",
9737bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 (void *)secondaryBuffer, (uint64_t)(secondary_fb));
97385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return skip_call;
97395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
97409a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto cb_renderpass = GetRenderPassState(dev_data, pSubCB->beginInfo.pInheritanceInfo->renderPass);
9741a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        if (cb_renderpass->renderPass != fb->createInfo.renderPass) {
9742a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis            skip_call |= validateRenderPassCompatibility(dev_data, secondaryBuffer, fb->renderPassCreateInfo.ptr(), secondaryBuffer,
9743fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes                                                         cb_renderpass->createInfo.ptr());
9744a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        }
97455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
97465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
97475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
97485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9749e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool validateSecondaryCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB, GLOBAL_CB_NODE *pSubCB) {
975083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
97515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_set<int> activeTypes;
97525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto queryObject : pCB->activeQueries) {
97535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto queryPoolData = dev_data->queryPoolMap.find(queryObject.pool);
97545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (queryPoolData != dev_data->queryPoolMap.end()) {
97555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (queryPoolData->second.createInfo.queryType == VK_QUERY_TYPE_PIPELINE_STATISTICS &&
97565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pSubCB->beginInfo.pInheritanceInfo) {
97575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                VkQueryPipelineStatisticFlags cmdBufStatistics = pSubCB->beginInfo.pInheritanceInfo->pipelineStatistics;
97585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if ((cmdBufStatistics & queryPoolData->second.createInfo.pipelineStatistics) != cmdBufStatistics) {
9759cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
9760cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         __LINE__, VALIDATION_ERROR_02065, "DS",
9761cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         "vkCmdExecuteCommands() called w/ invalid Cmd Buffer 0x%p "
9762cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         "which has invalid active query pool 0x%" PRIx64
9763cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         ". Pipeline statistics is being queried so the command "
9764cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         "buffer must have all bits set on the queryPool. %s",
9765cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         pCB->commandBuffer, reinterpret_cast<const uint64_t &>(queryPoolData->first),
9766cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         validation_error_map[VALIDATION_ERROR_02065]);
97675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
97685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
97695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            activeTypes.insert(queryPoolData->second.createInfo.queryType);
97705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
97715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
97725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto queryObject : pSubCB->startedQueries) {
97735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto queryPoolData = dev_data->queryPoolMap.find(queryObject.pool);
97745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (queryPoolData != dev_data->queryPoolMap.end() && activeTypes.count(queryPoolData->second.createInfo.queryType)) {
9775cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9776cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
9777cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "vkCmdExecuteCommands() called w/ invalid Cmd Buffer 0x%p "
9778cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "which has invalid active query pool 0x%" PRIx64
9779cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "of type %d but a query of that type has been started on "
9780cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "secondary Cmd Buffer 0x%p.",
9781cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 pCB->commandBuffer, reinterpret_cast<const uint64_t &>(queryPoolData->first),
9782cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 queryPoolData->second.createInfo.queryType, pSubCB->commandBuffer);
97835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
97845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
97857bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
97869a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto primary_pool = GetCommandPoolNode(dev_data, pCB->createInfo.commandPool);
97879a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto secondary_pool = GetCommandPoolNode(dev_data, pSubCB->createInfo.commandPool);
97887bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski    if (primary_pool && secondary_pool && (primary_pool->queueFamilyIndex != secondary_pool->queueFamilyIndex)) {
9789226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis        skip_call |=
9790226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9791226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    reinterpret_cast<uint64_t>(pSubCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_QUEUE_FAMILY, "DS",
9792226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    "vkCmdExecuteCommands(): Primary command buffer 0x%p"
9793226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    " created in queue family %d has secondary command buffer 0x%p created in queue family %d.",
9794226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    pCB->commandBuffer, primary_pool->queueFamilyIndex, pSubCB->commandBuffer, secondary_pool->queueFamilyIndex);
97957bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski    }
97967bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
979783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
97985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
97995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9800bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBuffersCount,
9801bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              const VkCommandBuffer *pCommandBuffers) {
980283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
980356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
9804b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
98059a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
98065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
98075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        GLOBAL_CB_NODE *pSubCB = NULL;
98085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < commandBuffersCount; i++) {
98099a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            pSubCB = GetCBNode(dev_data, pCommandBuffers[i]);
98100a8b955c23012196339f3c10ffedc631ea0f7c58Tobin Ehlis            assert(pSubCB);
98110a8b955c23012196339f3c10ffedc631ea0f7c58Tobin Ehlis            if (VK_COMMAND_BUFFER_LEVEL_PRIMARY == pSubCB->createInfo.level) {
981283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
98134b6738a6adb4e813d66234defee5d18b7c84340dMike Weiblen                                     __LINE__, VALIDATION_ERROR_00153, "DS",
981483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                     "vkCmdExecuteCommands() called w/ Primary Cmd Buffer 0x%p in element %u of pCommandBuffers "
98154b6738a6adb4e813d66234defee5d18b7c84340dMike Weiblen                                     "array. All cmd buffers in pCommandBuffers array must be secondary. %s",
9816226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                     pCommandBuffers[i], i, validation_error_map[VALIDATION_ERROR_00153]);
9817cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else if (pCB->activeRenderPass) {  // Secondary CB w/i RenderPass must have *CONTINUE_BIT set
98189a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto secondary_rp_state = GetRenderPassState(dev_data, pSubCB->beginInfo.pInheritanceInfo->renderPass);
98195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (!(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
982083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |= log_msg(
98215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
98224b6738a6adb4e813d66234defee5d18b7c84340dMike Weiblen                        (uint64_t)pCommandBuffers[i], __LINE__, VALIDATION_ERROR_02057, "DS",
9823414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                        "vkCmdExecuteCommands(): Secondary Command Buffer (0x%p) executed within render pass (0x%" PRIxLEAST64
98244b6738a6adb4e813d66234defee5d18b7c84340dMike Weiblen                        ") must have had vkBeginCommandBuffer() called w/ VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT set. %s",
9825226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        pCommandBuffers[i], (uint64_t)pCB->activeRenderPass->renderPass,
98264b6738a6adb4e813d66234defee5d18b7c84340dMike Weiblen                        validation_error_map[VALIDATION_ERROR_02057]);
98275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                } else {
98285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    // Make sure render pass is compatible with parent command buffer pass if has continue
9829127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                    if (pCB->activeRenderPass->renderPass != secondary_rp_state->renderPass) {
9830fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes                        skip_call |=
9831fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes                            validateRenderPassCompatibility(dev_data, commandBuffer, pCB->activeRenderPass->createInfo.ptr(),
9832127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                                                            pCommandBuffers[i], secondary_rp_state->createInfo.ptr());
9833a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                    }
98341af6125615cd6dd9735d32e2ee8684abeff28d41Tobin Ehlis                    //  If framebuffer for secondary CB is not NULL, then it must match active FB from primaryCB
983583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |= validateFramebuffer(dev_data, commandBuffer, pCB, pCommandBuffers[i], pSubCB);
98365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
98375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                string errorString = "";
98381af6125615cd6dd9735d32e2ee8684abeff28d41Tobin Ehlis                // secondaryCB must have been created w/ RP compatible w/ primaryCB active renderpass
9839127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                if ((pCB->activeRenderPass->renderPass != secondary_rp_state->renderPass) &&
9840fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes                    !verify_renderpass_compatibility(dev_data, pCB->activeRenderPass->createInfo.ptr(),
9841127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                                                     secondary_rp_state->createInfo.ptr(), errorString)) {
984283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |= log_msg(
98435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
98445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        (uint64_t)pCommandBuffers[i], __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE, "DS",
9845414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                        "vkCmdExecuteCommands(): Secondary Command Buffer (0x%p) w/ render pass (0x%" PRIxLEAST64
9846414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                        ") is incompatible w/ primary command buffer (0x%p) w/ render pass (0x%" PRIxLEAST64 ") due to: %s",
9847226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        pCommandBuffers[i], (uint64_t)pSubCB->beginInfo.pInheritanceInfo->renderPass, commandBuffer,
9848ee691f5c5fa87aac3750454d2bca2cb582e4e817Chris Forbes                        (uint64_t)pCB->activeRenderPass->renderPass, errorString.c_str());
98495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
98505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
98515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // TODO(mlentine): Move more logic into this method
985283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= validateSecondaryCommandBufferState(dev_data, pCB, pSubCB);
985351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            skip_call |= validateCommandBufferState(dev_data, pSubCB, "vkCmdExecuteCommands()", 0);
98545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Secondary cmdBuffers are considered pending execution starting w/
98555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // being recorded
98565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
98575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (dev_data->globalInFlightCmdBuffers.find(pSubCB->commandBuffer) != dev_data->globalInFlightCmdBuffers.end()) {
9858cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
9859cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)(pCB->commandBuffer), __LINE__,
9860cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         VALIDATION_ERROR_00154, "DS",
9861cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         "Attempt to simultaneously execute command buffer 0x%p"
9862cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         " without VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set! %s",
9863cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         pCB->commandBuffer, validation_error_map[VALIDATION_ERROR_00154]);
98645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
98655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT) {
98665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    // Warn that non-simultaneous secondary cmd buffer renders primary non-simultaneous
986783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |= log_msg(
98685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
98695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        (uint64_t)(pCommandBuffers[i]), __LINE__, DRAWSTATE_INVALID_CB_SIMULTANEOUS_USE, "DS",
9870226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "vkCmdExecuteCommands(): Secondary Command Buffer (0x%p) "
9871226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set and will cause primary command buffer "
9872226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "(0x%p) to be treated as if it does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT "
987383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                        "set, even though it does.",
9874226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        pCommandBuffers[i], pCB->commandBuffer);
98755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    pCB->beginInfo.flags &= ~VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
98765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
98775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
9878f71dd305f197826a61f398bff725267a20ea1d90Chris Forbes            if (!pCB->activeQueries.empty() && !dev_data->enabled_features.inheritedQueries) {
9879cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                skip_call |=
9880cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9881cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            reinterpret_cast<uint64_t>(pCommandBuffers[i]), __LINE__, VALIDATION_ERROR_02062, "DS",
9882cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "vkCmdExecuteCommands(): Secondary Command Buffer "
9883cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "(0x%p) cannot be submitted with a query in "
9884cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "flight and inherited queries not "
9885cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "supported on this device. %s",
9886cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            pCommandBuffers[i], validation_error_map[VALIDATION_ERROR_02062]);
98875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
98888567fecbf563420f5900ade277ca68908aa87259Tobin Ehlis            // Propagate layout transitions to the primary cmd buffer
98898567fecbf563420f5900ade277ca68908aa87259Tobin Ehlis            for (auto ilm_entry : pSubCB->imageLayoutMap) {
989055867dbad6ae423b3bd78c15f6771031a710b5adMark Lobodzinski                SetLayout(dev_data, pCB, ilm_entry.first, ilm_entry.second);
98918567fecbf563420f5900ade277ca68908aa87259Tobin Ehlis            }
98925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pSubCB->primaryCommandBuffer = pCB->commandBuffer;
98935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pCB->secondaryCommandBuffers.insert(pSubCB->commandBuffer);
98945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->globalInFlightCmdBuffers.insert(pSubCB->commandBuffer);
9895d4ee9fdb2def1e9dc70c5627c9103e264471b8ebMichael Lentine            for (auto &function : pSubCB->queryUpdates) {
9896d4ee9fdb2def1e9dc70c5627c9103e264471b8ebMichael Lentine                pCB->queryUpdates.push_back(function);
9897d4ee9fdb2def1e9dc70c5627c9103e264471b8ebMichael Lentine            }
98985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
98999bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt        skip_call |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdExecuteComands", VALIDATION_ERROR_00163);
990029f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_EXECUTECOMMANDS, "vkCmdExecuteComands()");
99011ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_EXECUTECOMMANDS);
99025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9903b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
9904cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdExecuteCommands(commandBuffer, commandBuffersCount, pCommandBuffers);
99055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
99065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9907bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL MapMemory(VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size, VkFlags flags,
9908bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         void **ppData) {
990956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
99105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9911e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
99125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
9913b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
99149a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
9915cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    if (mem_info) {
9916f541bf53dee6daf82a4c8304354eac599a884d29Tobin Ehlis        // TODO : This could me more fine-grained to track just region that is valid
9917f541bf53dee6daf82a4c8304354eac599a884d29Tobin Ehlis        mem_info->global_valid = true;
9918623548a271287ae55415e45e3c654ee66d4e79ffTobin Ehlis        auto end_offset = (VK_WHOLE_SIZE == size) ? mem_info->alloc_info.allocationSize - 1 : offset + size - 1;
9919c3340a06ecac4d7b9540592cae339f8fc224d0b1Mark Lobodzinski        skip_call |= ValidateMapImageLayouts(dev_data, device, mem_info, offset, end_offset);
9920cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis        // TODO : Do we need to create new "bound_range" for the mapped range?
9921623548a271287ae55415e45e3c654ee66d4e79ffTobin Ehlis        SetMemRangesValid(dev_data, mem_info, offset, end_offset);
9922cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis        if ((dev_data->phys_dev_mem_props.memoryTypes[mem_info->alloc_info.memoryTypeIndex].propertyFlags &
9923b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis             VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) {
99242fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen            skip_call = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
99252fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                (uint64_t)mem, __LINE__, VALIDATION_ERROR_00629, "MEM",
99262fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                "Mapping Memory without VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT set: mem obj 0x%" PRIxLEAST64 ". %s",
99272fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                (uint64_t)mem, validation_error_map[VALIDATION_ERROR_00629]);
99285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
99295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9930f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis    skip_call |= ValidateMapMemRange(dev_data, mem, offset, size);
9931b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
99325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9933e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    if (!skip_call) {
99344a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.MapMemory(device, mem, offset, size, flags, ppData);
99357c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis        if (VK_SUCCESS == result) {
99367c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis            lock.lock();
9937cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis            // TODO : What's the point of this range? See comment on creating new "bound_range" above, which may replace this
99387c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis            storeMemRanges(dev_data, mem, offset, size);
99395f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            initializeAndTrackMemory(dev_data, mem, offset, size, ppData);
99407c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis            lock.unlock();
99417c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis        }
99425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
99435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
99445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
99455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
994689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL UnmapMemory(VkDevice device, VkDeviceMemory mem) {
994756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
994883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
99495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9950b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
99518860b85a52096f9f9b28616bc37feed505497a54Chris Forbes    skip_call |= deleteMemRanges(dev_data, mem);
9952b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
995383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (!skip_call) {
99544a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.UnmapMemory(device, mem);
99555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
99565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
99575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
99588860b85a52096f9f9b28616bc37feed505497a54Chris Forbesstatic bool validateMemoryIsMapped(layer_data *dev_data, const char *funcName, uint32_t memRangeCount,
9959e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                                   const VkMappedMemoryRange *pMemRanges) {
9960c7ee6f2fe100c1aacfaa0872832717c906bb8a4aMark Lobodzinski    bool skip = false;
99615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < memRangeCount; ++i) {
99629a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto mem_info = GetMemObjInfo(dev_data, pMemRanges[i].memory);
996357fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        if (mem_info) {
9964f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski            if (pMemRanges[i].size == VK_WHOLE_SIZE) {
9965f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                if (mem_info->mem_range.offset > pMemRanges[i].offset) {
9966cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
9967cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)pMemRanges[i].memory, __LINE__,
9968cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    VALIDATION_ERROR_00643, "MEM", "%s: Flush/Invalidate offset (" PRINTF_SIZE_T_SPECIFIER
9969cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                                   ") is less than Memory Object's offset "
9970cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                                   "(" PRINTF_SIZE_T_SPECIFIER "). %s",
9971cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    funcName, static_cast<size_t>(pMemRanges[i].offset),
9972cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    static_cast<size_t>(mem_info->mem_range.offset), validation_error_map[VALIDATION_ERROR_00643]);
9973f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                }
9974f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski            } else {
9975f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                const uint64_t data_end = (mem_info->mem_range.size == VK_WHOLE_SIZE)
9976f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                              ? mem_info->alloc_info.allocationSize
9977f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                              : (mem_info->mem_range.offset + mem_info->mem_range.size);
9978f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                if ((mem_info->mem_range.offset > pMemRanges[i].offset) ||
9979f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                    (data_end < (pMemRanges[i].offset + pMemRanges[i].size))) {
9980c7ee6f2fe100c1aacfaa0872832717c906bb8a4aMark Lobodzinski                    skip |=
9981f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
9982f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                (uint64_t)pMemRanges[i].memory, __LINE__, VALIDATION_ERROR_00642, "MEM",
9983f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                "%s: Flush/Invalidate size or offset (" PRINTF_SIZE_T_SPECIFIER ", " PRINTF_SIZE_T_SPECIFIER
9984f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                ") exceed the Memory Object's upper-bound "
9985f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                "(" PRINTF_SIZE_T_SPECIFIER "). %s",
9986f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                funcName, static_cast<size_t>(pMemRanges[i].offset + pMemRanges[i].size),
9987f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                static_cast<size_t>(pMemRanges[i].offset), static_cast<size_t>(data_end),
9988f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                validation_error_map[VALIDATION_ERROR_00642]);
9989f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                }
99905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
99915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
99925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9993c7ee6f2fe100c1aacfaa0872832717c906bb8a4aMark Lobodzinski    return skip;
99945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
99955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9996bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinskistatic bool ValidateAndCopyNoncoherentMemoryToDriver(layer_data *dev_data, uint32_t mem_range_count,
9997bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                                     const VkMappedMemoryRange *mem_ranges) {
9998bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski    bool skip = false;
9999bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski    for (uint32_t i = 0; i < mem_range_count; ++i) {
100009a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto mem_info = GetMemObjInfo(dev_data, mem_ranges[i].memory);
1000157fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        if (mem_info) {
100025f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            if (mem_info->shadow_copy) {
100035f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                VkDeviceSize size = (mem_info->mem_range.size != VK_WHOLE_SIZE)
100045f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                        ? mem_info->mem_range.size
10005d8a53ade6b5501256798a8b4ec0bc14f72adc1faTobin Ehlis                                        : (mem_info->alloc_info.allocationSize - mem_info->mem_range.offset);
100065f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                char *data = static_cast<char *>(mem_info->shadow_copy);
100075f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                for (uint64_t j = 0; j < mem_info->shadow_pad_size; ++j) {
100085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    if (data[j] != NoncoherentMemoryFillValue) {
10009bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
10010bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                        VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)mem_ranges[i].memory, __LINE__,
10011bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                        MEMTRACK_INVALID_MAP, "MEM", "Memory underflow was detected on mem obj 0x%" PRIxLEAST64,
10012bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                        (uint64_t)mem_ranges[i].memory);
100135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
100145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
100155f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                for (uint64_t j = (size + mem_info->shadow_pad_size); j < (2 * mem_info->shadow_pad_size + size); ++j) {
100165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    if (data[j] != NoncoherentMemoryFillValue) {
10017bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
10018bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                        VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)mem_ranges[i].memory, __LINE__,
10019bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                        MEMTRACK_INVALID_MAP, "MEM", "Memory overflow was detected on mem obj 0x%" PRIxLEAST64,
10020bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                        (uint64_t)mem_ranges[i].memory);
100215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
100225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
100235f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                memcpy(mem_info->p_driver_data, static_cast<void *>(data + mem_info->shadow_pad_size), (size_t)(size));
100245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
100255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
100265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10027bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski    return skip;
100285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
100295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10030bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinskistatic void CopyNoncoherentMemoryFromDriver(layer_data *dev_data, uint32_t mem_range_count, const VkMappedMemoryRange *mem_ranges) {
10031bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski    for (uint32_t i = 0; i < mem_range_count; ++i) {
100329a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto mem_info = GetMemObjInfo(dev_data, mem_ranges[i].memory);
100335f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski        if (mem_info && mem_info->shadow_copy) {
100345f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            VkDeviceSize size = (mem_info->mem_range.size != VK_WHOLE_SIZE)
100355f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                    ? mem_info->mem_range.size
100365f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                    : (mem_info->alloc_info.allocationSize - mem_ranges[i].offset);
100375f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            char *data = static_cast<char *>(mem_info->shadow_copy);
100385f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            memcpy(data + mem_info->shadow_pad_size, mem_info->p_driver_data, (size_t)(size));
100399e21e56fc23ade48efd3752d2e2729895eb90349Mark Lobodzinski        }
100409e21e56fc23ade48efd3752d2e2729895eb90349Mark Lobodzinski    }
100419e21e56fc23ade48efd3752d2e2729895eb90349Mark Lobodzinski}
100429e21e56fc23ade48efd3752d2e2729895eb90349Mark Lobodzinski
10043ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinskistatic bool ValidateMappedMemoryRangeDeviceLimits(layer_data *dev_data, const char *func_name, uint32_t mem_range_count,
10044ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                                                  const VkMappedMemoryRange *mem_ranges) {
10045ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski    bool skip = false;
10046ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski    for (uint32_t i = 0; i < mem_range_count; ++i) {
10047ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski        uint64_t atom_size = dev_data->phys_dev_properties.properties.limits.nonCoherentAtomSize;
10048ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski        if (vk_safe_modulo(mem_ranges[i].offset, atom_size) != 0) {
10049ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
10050ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            __LINE__, VALIDATION_ERROR_00644, "MEM",
10051ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            "%s: Offset in pMemRanges[%d] is 0x%" PRIxLEAST64
10052ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            ", which is not a multiple of VkPhysicalDeviceLimits::nonCoherentAtomSize (0x%" PRIxLEAST64 "). %s",
10053ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            func_name, i, mem_ranges[i].offset, atom_size, validation_error_map[VALIDATION_ERROR_00644]);
10054ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski        }
10055ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski        if ((mem_ranges[i].size != VK_WHOLE_SIZE) && (vk_safe_modulo(mem_ranges[i].size, atom_size) != 0)) {
10056ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
10057ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            __LINE__, VALIDATION_ERROR_00645, "MEM",
10058ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            "%s: Size in pMemRanges[%d] is 0x%" PRIxLEAST64
10059ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            ", which is not a multiple of VkPhysicalDeviceLimits::nonCoherentAtomSize (0x%" PRIxLEAST64 "). %s",
10060ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            func_name, i, mem_ranges[i].size, atom_size, validation_error_map[VALIDATION_ERROR_00645]);
10061ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski        }
10062ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski    }
10063ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski    return skip;
10064ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski}
10065ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski
1006680e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinskistatic bool PreCallValidateFlushMappedMemoryRanges(layer_data *dev_data, uint32_t mem_range_count,
1006780e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski                                                   const VkMappedMemoryRange *mem_ranges) {
1006880e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    bool skip = false;
1006980e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    std::lock_guard<std::mutex> lock(global_lock);
1007080e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    skip |= ValidateAndCopyNoncoherentMemoryToDriver(dev_data, mem_range_count, mem_ranges);
1007180e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    skip |= validateMemoryIsMapped(dev_data, "vkFlushMappedMemoryRanges", mem_range_count, mem_ranges);
1007280e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    return skip;
1007380e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski}
1007480e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski
10075bba0de708d942e9a2187158915856995db1c5a4dMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL FlushMappedMemoryRanges(VkDevice device, uint32_t memRangeCount,
10076bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                                       const VkMappedMemoryRange *pMemRanges) {
100775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
1007856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
100795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1008080e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    if (!PreCallValidateFlushMappedMemoryRanges(dev_data, memRangeCount, pMemRanges)) {
100814a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.FlushMappedMemoryRanges(device, memRangeCount, pMemRanges);
100825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
100835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
100845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
100855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1008680e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinskistatic bool PreCallValidateInvalidateMappedMemoryRanges(layer_data *dev_data, uint32_t mem_range_count,
1008780e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski                                                        const VkMappedMemoryRange *mem_ranges) {
1008880e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    bool skip = false;
1008980e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    std::lock_guard<std::mutex> lock(global_lock);
1009080e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    skip |= validateMemoryIsMapped(dev_data, "vkInvalidateMappedMemoryRanges", mem_range_count, mem_ranges);
1009180e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    return skip;
1009280e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski}
1009380e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski
1009480e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinskistatic void PostCallRecordInvalidateMappedMemoryRanges(layer_data *dev_data, uint32_t mem_range_count,
1009580e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski                                                       const VkMappedMemoryRange *mem_ranges) {
1009680e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    std::lock_guard<std::mutex> lock(global_lock);
1009780e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    // Update our shadow copy with modified driver data
1009880e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    CopyNoncoherentMemoryFromDriver(dev_data, mem_range_count, mem_ranges);
1009980e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski}
1010080e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski
10101bba0de708d942e9a2187158915856995db1c5a4dMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL InvalidateMappedMemoryRanges(VkDevice device, uint32_t memRangeCount,
10102bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                                            const VkMappedMemoryRange *pMemRanges) {
101035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
1010456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
101055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1010680e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    if (!PreCallValidateInvalidateMappedMemoryRanges(dev_data, memRangeCount, pMemRanges)) {
101074a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.InvalidateMappedMemoryRanges(device, memRangeCount, pMemRanges);
1010880e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski        if (result == VK_SUCCESS) {
1010980e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski            PostCallRecordInvalidateMappedMemoryRanges(dev_data, memRangeCount, pMemRanges);
1011080e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski        }
101115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
101125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
101135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
101145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10115341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Strattonstatic bool PreCallValidateBindImageMemory(layer_data *dev_data, VkImage image, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
101160109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski    bool skip = false;
10117b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
10118341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton
101199a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto image_state = GetImageState(dev_data, image);
101201facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (image_state) {
1012194c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis        // Track objects tied to memory
1012247aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski        uint64_t image_handle = reinterpret_cast<uint64_t &>(image);
101230109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski        skip = SetMemBinding(dev_data, mem, image_handle, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, "vkBindImageMemory");
10124ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis        if (!image_state->memory_requirements_checked) {
10125ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            // There's not an explicit requirement in the spec to call vkGetImageMemoryRequirements() prior to calling
10126341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton            // BindImageMemory but it's implied in that memory being bound must conform with VkMemoryRequirements from
10127341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton            // vkGetImageMemoryRequirements()
101280109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
101290109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski                            image_handle, __LINE__, DRAWSTATE_INVALID_IMAGE, "DS",
101300109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski                            "vkBindImageMemory(): Binding memory to image 0x%" PRIxLEAST64
101310109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski                            " but vkGetImageMemoryRequirements() has not been called on that image.",
101320109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski                            image_handle);
10133ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            // Make the call for them so we can verify the state
10134ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            lock.unlock();
10135341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton            dev_data->dispatch_table.GetImageMemoryRequirements(dev_data->device, image, &image_state->requirements);
10136ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            lock.lock();
10137ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis        }
1013847aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
1013947aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski        // Track and validate bound memory range information
101409a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto mem_info = GetMemObjInfo(dev_data, mem);
1014157fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        if (mem_info) {
101420109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski            skip |= InsertImageMemoryRange(dev_data, image, mem_info, memoryOffset, image_state->requirements,
101437992c34b28dd617787f0e4d34fd023f894495edbCort Stratton                                           image_state->createInfo.tiling == VK_IMAGE_TILING_LINEAR, "vkBindImageMemory");
101440109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski            skip |= ValidateMemoryTypes(dev_data, mem_info, image_state->requirements.memoryTypeBits, "vkBindImageMemory",
101450109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski                                        VALIDATION_ERROR_00806);
1014647aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski        }
10147341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    }
10148341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    return skip;
10149341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton}
1015047aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
10151341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Strattonstatic void PostCallRecordBindImageMemory(layer_data *dev_data, VkImage image, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
10152341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    std::unique_lock<std::mutex> lock(global_lock);
10153341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    auto image_state = GetImageState(dev_data, image);
10154341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    if (image_state) {
10155341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton        image_state->binding.mem = mem;
10156341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton        image_state->binding.offset = memoryOffset;
10157341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton        image_state->binding.size = image_state->requirements.size;
10158341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    }
10159341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton}
10160341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton
10161341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort StrattonVKAPI_ATTR VkResult VKAPI_CALL BindImageMemory(VkDevice device, VkImage image, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
10162341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
10163341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
10164341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    bool skip = PreCallValidateBindImageMemory(dev_data, image, mem, memoryOffset);
10165341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    if (!skip) {
10166341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton        result = dev_data->dispatch_table.BindImageMemory(device, image, mem, memoryOffset);
10167341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton        if (result == VK_SUCCESS) {
10168341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton            PostCallRecordBindImageMemory(dev_data, image, mem, memoryOffset);
1016994c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis        }
101705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
101715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
101725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
101735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1017489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL SetEvent(VkDevice device, VkEvent event) {
101753ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis    bool skip_call = false;
101763ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
1017756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
10178b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
101799a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto event_state = GetEventNode(dev_data, event);
101804710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis    if (event_state) {
101814710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        event_state->needsSignaled = false;
101824710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        event_state->stageMask = VK_PIPELINE_STAGE_HOST_BIT;
101834710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        if (event_state->write_in_use) {
101843ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT,
101853ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis                                 reinterpret_cast<const uint64_t &>(event), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
10186414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                                 "Cannot call vkSetEvent() on event 0x%" PRIxLEAST64 " that is already in use by a command buffer.",
101873ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis                                 reinterpret_cast<const uint64_t &>(event));
101883ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis        }
101893ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis    }
10190b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
101916fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    // Host setting event is visible to all queues immediately so update stageMask for any queue that's seen this event
101926fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    // TODO : For correctness this needs separate fix to verify that app doesn't make incorrect assumptions about the
101936fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    // ordering of this command in relation to vkCmd[Set|Reset]Events (see GH297)
101946fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    for (auto queue_data : dev_data->queueMap) {
101956fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis        auto event_entry = queue_data.second.eventToStageMap.find(event);
101966fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis        if (event_entry != queue_data.second.eventToStageMap.end()) {
101976fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis            event_entry->second |= VK_PIPELINE_STAGE_HOST_BIT;
101986fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis        }
101996fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    }
10200cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) result = dev_data->dispatch_table.SetEvent(device, event);
102015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
102025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
102035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10204bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL QueueBindSparse(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo *pBindInfo,
10205bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                               VkFence fence) {
1020656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
102075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
10208e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
10209b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
102109a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pFence = GetFenceNode(dev_data, fence);
102119a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pQueue = GetQueueState(dev_data, queue);
10212651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
102134b38d3aa8b6be6a7f5bebb472ab439da0562824fTobin Ehlis    // First verify that fence is not in use
10214651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    skip_call |= ValidateFenceForSubmit(dev_data, pFence);
10215651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
102169867daedbf52debc77d6568162ee21e071699b80Chris Forbes    if (pFence) {
102179867daedbf52debc77d6568162ee21e071699b80Chris Forbes        SubmitFence(pQueue, pFence, bindInfoCount);
102184b38d3aa8b6be6a7f5bebb472ab439da0562824fTobin Ehlis    }
10219651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
102201344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis    for (uint32_t bindIdx = 0; bindIdx < bindInfoCount; ++bindIdx) {
102211344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        const VkBindSparseInfo &bindInfo = pBindInfo[bindIdx];
102225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Track objects tied to memory
102231344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t j = 0; j < bindInfo.bufferBindCount; j++) {
102241344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis            for (uint32_t k = 0; k < bindInfo.pBufferBinds[j].bindCount; k++) {
10225f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                auto sparse_binding = bindInfo.pBufferBinds[j].pBinds[k];
10226f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                if (SetSparseMemBinding(dev_data, {sparse_binding.memory, sparse_binding.memoryOffset, sparse_binding.size},
10227f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                                        (uint64_t)bindInfo.pBufferBinds[j].buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
10228f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                                        "vkQueueBindSparse"))
10229e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                    skip_call = true;
102305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
102315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
102321344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t j = 0; j < bindInfo.imageOpaqueBindCount; j++) {
102331344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis            for (uint32_t k = 0; k < bindInfo.pImageOpaqueBinds[j].bindCount; k++) {
10234f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                auto sparse_binding = bindInfo.pImageOpaqueBinds[j].pBinds[k];
10235f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                if (SetSparseMemBinding(dev_data, {sparse_binding.memory, sparse_binding.memoryOffset, sparse_binding.size},
10236f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                                        (uint64_t)bindInfo.pImageOpaqueBinds[j].image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
10237f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                                        "vkQueueBindSparse"))
10238e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                    skip_call = true;
102395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
102405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
102411344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t j = 0; j < bindInfo.imageBindCount; j++) {
102421344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis            for (uint32_t k = 0; k < bindInfo.pImageBinds[j].bindCount; k++) {
10243f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                auto sparse_binding = bindInfo.pImageBinds[j].pBinds[k];
10244f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                // TODO: This size is broken for non-opaque bindings, need to update to comprehend full sparse binding data
10245f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                VkDeviceSize size = sparse_binding.extent.depth * sparse_binding.extent.height * sparse_binding.extent.width * 4;
10246f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                if (SetSparseMemBinding(dev_data, {sparse_binding.memory, sparse_binding.memoryOffset, size},
10247f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                                        (uint64_t)bindInfo.pImageBinds[j].image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
10248f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                                        "vkQueueBindSparse"))
10249e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                    skip_call = true;
102505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
102515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
102529867daedbf52debc77d6568162ee21e071699b80Chris Forbes
102539867daedbf52debc77d6568162ee21e071699b80Chris Forbes        std::vector<SEMAPHORE_WAIT> semaphore_waits;
102549867daedbf52debc77d6568162ee21e071699b80Chris Forbes        std::vector<VkSemaphore> semaphore_signals;
102551344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t i = 0; i < bindInfo.waitSemaphoreCount; ++i) {
1025601a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            VkSemaphore semaphore = bindInfo.pWaitSemaphores[i];
102579a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
1025801a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            if (pSemaphore) {
1025901a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes                if (pSemaphore->signaled) {
102609867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    if (pSemaphore->signaler.first != VK_NULL_HANDLE) {
102619867daedbf52debc77d6568162ee21e071699b80Chris Forbes                        semaphore_waits.push_back({semaphore, pSemaphore->signaler.first, pSemaphore->signaler.second});
102629867daedbf52debc77d6568162ee21e071699b80Chris Forbes                        pSemaphore->in_use.fetch_add(1);
102639867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    }
102649867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->signaler.first = VK_NULL_HANDLE;
1026501a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes                    pSemaphore->signaled = false;
102661344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                } else {
10267226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    skip_call |= log_msg(
10268226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
10269226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        reinterpret_cast<const uint64_t &>(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
10270226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "vkQueueBindSparse: Queue 0x%p is waiting on semaphore 0x%" PRIx64 " that has no way to be signaled.",
10271226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        queue, reinterpret_cast<const uint64_t &>(semaphore));
102725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
102735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
102745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
102751344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t i = 0; i < bindInfo.signalSemaphoreCount; ++i) {
1027601a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            VkSemaphore semaphore = bindInfo.pSignalSemaphores[i];
102779a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
1027801a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            if (pSemaphore) {
1027901a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes                if (pSemaphore->signaled) {
102805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    skip_call =
102815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
102821344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                                reinterpret_cast<const uint64_t &>(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
10283226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                "vkQueueBindSparse: Queue 0x%p is signaling semaphore 0x%" PRIx64
102841344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                                ", but that semaphore is already signaled.",
10285226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                queue, reinterpret_cast<const uint64_t &>(semaphore));
10286bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                } else {
102879867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->signaler.first = queue;
102889867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->signaler.second = pQueue->seq + pQueue->submissions.size() + 1;
102899867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->signaled = true;
102909867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->in_use.fetch_add(1);
102919867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    semaphore_signals.push_back(semaphore);
102929867daedbf52debc77d6568162ee21e071699b80Chris Forbes                }
102935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
102945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
102959867daedbf52debc77d6568162ee21e071699b80Chris Forbes
10296bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pQueue->submissions.emplace_back(std::vector<VkCommandBuffer>(), semaphore_waits, semaphore_signals,
102979867daedbf52debc77d6568162ee21e071699b80Chris Forbes                                         bindIdx == bindInfoCount - 1 ? fence : VK_NULL_HANDLE);
102985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
102999867daedbf52debc77d6568162ee21e071699b80Chris Forbes
103009867daedbf52debc77d6568162ee21e071699b80Chris Forbes    if (pFence && !bindInfoCount) {
103019867daedbf52debc77d6568162ee21e071699b80Chris Forbes        // No work to do, just dropping a fence in the queue by itself.
10302bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pQueue->submissions.emplace_back(std::vector<VkCommandBuffer>(), std::vector<SEMAPHORE_WAIT>(), std::vector<VkSemaphore>(),
103039867daedbf52debc77d6568162ee21e071699b80Chris Forbes                                         fence);
103049867daedbf52debc77d6568162ee21e071699b80Chris Forbes    }
103059867daedbf52debc77d6568162ee21e071699b80Chris Forbes
10306b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
103075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10308cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) return dev_data->dispatch_table.QueueBindSparse(queue, bindInfoCount, pBindInfo, fence);
103095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
103105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
103115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
103125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1031389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateSemaphore(VkDevice device, const VkSemaphoreCreateInfo *pCreateInfo,
1031489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                               const VkAllocationCallbacks *pAllocator, VkSemaphore *pSemaphore) {
1031556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
103164a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateSemaphore(device, pCreateInfo, pAllocator, pSemaphore);
103175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
10318b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
10319bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        SEMAPHORE_NODE *sNode = &dev_data->semaphoreMap[*pSemaphore];
103209867daedbf52debc77d6568162ee21e071699b80Chris Forbes        sNode->signaler.first = VK_NULL_HANDLE;
103219867daedbf52debc77d6568162ee21e071699b80Chris Forbes        sNode->signaler.second = 0;
103221344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        sNode->signaled = false;
103235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
103245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
103255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
103265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10327bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateEvent(VkDevice device, const VkEventCreateInfo *pCreateInfo,
10328bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           const VkAllocationCallbacks *pAllocator, VkEvent *pEvent) {
1032956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
103304a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateEvent(device, pCreateInfo, pAllocator, pEvent);
103315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
10332b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
103335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->eventMap[*pEvent].needsSignaled = false;
10334293ecfc5e69ed3978a8c04518166d828294870a4Tony Barbour        dev_data->eventMap[*pEvent].write_in_use = 0;
103355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->eventMap[*pEvent].stageMask = VkPipelineStageFlags(0);
103365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
103375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
103385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
103395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
103409ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinskistatic bool PreCallValidateCreateSwapchainKHR(layer_data *dev_data, const char *func_name,
103419ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                                              VkSwapchainCreateInfoKHR const *pCreateInfo, SURFACE_STATE *surface_state,
103429ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                                              SWAPCHAIN_NODE *old_swapchain_state) {
10343d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    auto most_recent_swapchain = surface_state->swapchain ? surface_state->swapchain : surface_state->old_swapchain;
10344d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes
103454bd5f453535de3d3423ff1f9995b4acb15f791d2Chris Forbes    // TODO: revisit this. some of these rules are being relaxed.
10346d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    if (most_recent_swapchain != old_swapchain_state || (surface_state->old_swapchain && surface_state->swapchain)) {
10347d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
10348d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes                    reinterpret_cast<uint64_t>(dev_data->device), __LINE__, DRAWSTATE_SWAPCHAIN_ALREADY_EXISTS, "DS",
103499ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    "%s: surface has an existing swapchain other than oldSwapchain", func_name))
10350d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes            return true;
10351d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    }
10352d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    if (old_swapchain_state && old_swapchain_state->createInfo.surface != pCreateInfo->surface) {
10353d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
10354d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes                    reinterpret_cast<uint64_t const &>(pCreateInfo->oldSwapchain), __LINE__, DRAWSTATE_SWAPCHAIN_WRONG_SURFACE,
103559ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    "DS", "%s: pCreateInfo->oldSwapchain's surface is not pCreateInfo->surface", func_name))
10356d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes            return true;
10357d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    }
103589a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(dev_data->instance_data, dev_data->physical_device);
103597de258f87ca1192db116a66b209253793d276ebcChris Forbes    if (physical_device_state->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState == UNCALLED) {
103607de258f87ca1192db116a66b209253793d276ebcChris Forbes        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
103617de258f87ca1192db116a66b209253793d276ebcChris Forbes                    reinterpret_cast<uint64_t>(dev_data->physical_device), __LINE__, DRAWSTATE_SWAPCHAIN_CREATE_BEFORE_QUERY, "DS",
103629ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    "%s: surface capabilities not retrieved for this physical device", func_name))
103637de258f87ca1192db116a66b209253793d276ebcChris Forbes            return true;
10364cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    } else {  // have valid capabilities
103655c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        auto &capabilities = physical_device_state->surfaceCapabilities;
103669ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->minImageCount against VkSurfaceCapabilitiesKHR::{min|max}ImageCount:
103672fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen        if (pCreateInfo->minImageCount < capabilities.minImageCount) {
103682fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
103692fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02331, "DS",
103709ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with minImageCount = %d, which is outside the bounds returned "
103712fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        "by vkGetPhysicalDeviceSurfaceCapabilitiesKHR() (i.e. minImageCount = %d, maxImageCount = %d). %s",
103729ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->minImageCount, capabilities.minImageCount, capabilities.maxImageCount,
103732fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        validation_error_map[VALIDATION_ERROR_02331]))
103742fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                return true;
103752fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen        }
103762fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen
103772fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen        if ((capabilities.maxImageCount > 0) && (pCreateInfo->minImageCount > capabilities.maxImageCount)) {
103785c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
103792fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02332, "DS",
103809ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with minImageCount = %d, which is outside the bounds returned "
103812fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        "by vkGetPhysicalDeviceSurfaceCapabilitiesKHR() (i.e. minImageCount = %d, maxImageCount = %d). %s",
103829ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->minImageCount, capabilities.minImageCount, capabilities.maxImageCount,
103832fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        validation_error_map[VALIDATION_ERROR_02332]))
103845c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
103855c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
103862fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen
103879ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->imageExtent against VkSurfaceCapabilitiesKHR::{current|min|max}ImageExtent:
103882e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill        if ((capabilities.currentExtent.width == kSurfaceSizeFromSwapchain) &&
103892e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill            ((pCreateInfo->imageExtent.width < capabilities.minImageExtent.width) ||
103902e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill             (pCreateInfo->imageExtent.width > capabilities.maxImageExtent.width) ||
103912e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill             (pCreateInfo->imageExtent.height < capabilities.minImageExtent.height) ||
103922e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill             (pCreateInfo->imageExtent.height > capabilities.maxImageExtent.height))) {
103935c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
103942fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02334, "DS",
103959ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with imageExtent = (%d,%d), which is outside the bounds returned by "
103969ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "vkGetPhysicalDeviceSurfaceCapabilitiesKHR(): currentExtent = (%d,%d), minImageExtent = (%d,%d), "
103979ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "maxImageExtent = (%d,%d). %s",
103989ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->imageExtent.width, pCreateInfo->imageExtent.height,
103999ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        capabilities.currentExtent.width, capabilities.currentExtent.height, capabilities.minImageExtent.width,
104009ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        capabilities.minImageExtent.height, capabilities.maxImageExtent.width, capabilities.maxImageExtent.height,
104012fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        validation_error_map[VALIDATION_ERROR_02334]))
104025c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
104035c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
104042e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill        if ((capabilities.currentExtent.width != kSurfaceSizeFromSwapchain) &&
104052e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill            ((pCreateInfo->imageExtent.width != capabilities.currentExtent.width) ||
104062e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill             (pCreateInfo->imageExtent.height != capabilities.currentExtent.height))) {
104075c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
104082fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02334, "DS",
104099ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with imageExtent = (%d,%d), which is not equal to the currentExtent = (%d,%d) returned by "
104109ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "vkGetPhysicalDeviceSurfaceCapabilitiesKHR(). %s",
104119ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->imageExtent.width, pCreateInfo->imageExtent.height,
104129ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        capabilities.currentExtent.width, capabilities.currentExtent.height,
104132fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        validation_error_map[VALIDATION_ERROR_02334]))
104145c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
104155c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
104169ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // pCreateInfo->preTransform should have exactly one bit set, and that bit must also be set in
104179ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // VkSurfaceCapabilitiesKHR::supportedTransforms.
104185c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        if (!pCreateInfo->preTransform || (pCreateInfo->preTransform & (pCreateInfo->preTransform - 1)) ||
104195c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            !(pCreateInfo->preTransform & capabilities.supportedTransforms)) {
104209ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            // This is an error situation; one for which we'd like to give the developer a helpful, multi-line error message.  Build
104219ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            // it up a little at a time, and then log it:
104225c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            std::string errorString = "";
104235c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            char str[1024];
104245c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            // Here's the first part of the message:
104259ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            sprintf(str, "%s called with a non-supported pCreateInfo->preTransform (i.e. %s).  Supported values are:\n", func_name,
104265c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    string_VkSurfaceTransformFlagBitsKHR(pCreateInfo->preTransform));
104275c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            errorString += str;
104285c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            for (int i = 0; i < 32; i++) {
104295c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                // Build up the rest of the message:
104305c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                if ((1 << i) & capabilities.supportedTransforms) {
104315c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    const char *newStr = string_VkSurfaceTransformFlagBitsKHR((VkSurfaceTransformFlagBitsKHR)(1 << i));
104325c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    sprintf(str, "    %s\n", newStr);
104335c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    errorString += str;
104345c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                }
104355c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            }
104365c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            // Log the message that we've built up:
104375c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
104382fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t &>(dev_data->device), __LINE__, VALIDATION_ERROR_02339, "DS", "%s. %s",
104392fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        errorString.c_str(), validation_error_map[VALIDATION_ERROR_02339]))
104405c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
104415c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
104427b0d28d116977b91892f354e002edd760bdb86cbChris Forbes
104439ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // pCreateInfo->compositeAlpha should have exactly one bit set, and that bit must also be set in
104449ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // VkSurfaceCapabilitiesKHR::supportedCompositeAlpha
104455c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        if (!pCreateInfo->compositeAlpha || (pCreateInfo->compositeAlpha & (pCreateInfo->compositeAlpha - 1)) ||
104465c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            !((pCreateInfo->compositeAlpha) & capabilities.supportedCompositeAlpha)) {
104479ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            // This is an error situation; one for which we'd like to give the developer a helpful, multi-line error message.  Build
104489ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            // it up a little at a time, and then log it:
104495c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            std::string errorString = "";
104505c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            char str[1024];
104515c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            // Here's the first part of the message:
104529ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            sprintf(str, "%s called with a non-supported pCreateInfo->compositeAlpha (i.e. %s).  Supported values are:\n",
104539ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    func_name, string_VkCompositeAlphaFlagBitsKHR(pCreateInfo->compositeAlpha));
104545c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            errorString += str;
104555c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            for (int i = 0; i < 32; i++) {
104565c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                // Build up the rest of the message:
104575c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                if ((1 << i) & capabilities.supportedCompositeAlpha) {
104585c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    const char *newStr = string_VkCompositeAlphaFlagBitsKHR((VkCompositeAlphaFlagBitsKHR)(1 << i));
104595c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    sprintf(str, "    %s\n", newStr);
104605c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    errorString += str;
104615c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                }
104625c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            }
104635c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            // Log the message that we've built up:
104645c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
104652fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t &>(dev_data->device), __LINE__, VALIDATION_ERROR_02340, "DS", "%s. %s",
104662fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        errorString.c_str(), validation_error_map[VALIDATION_ERROR_02340]))
104675c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
104685c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
104699ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->imageArrayLayers against VkSurfaceCapabilitiesKHR::maxImageArrayLayers:
104705c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        if ((pCreateInfo->imageArrayLayers < 1) || (pCreateInfo->imageArrayLayers > capabilities.maxImageArrayLayers)) {
104715c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
104722fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02335, "DS",
104739ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with a non-supported imageArrayLayers (i.e. %d).  Minimum value is 1, maximum value is %d. %s",
104749ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->imageArrayLayers, capabilities.maxImageArrayLayers,
104752fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        validation_error_map[VALIDATION_ERROR_02335]))
104765c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
104775c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
104789ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->imageUsage against VkSurfaceCapabilitiesKHR::supportedUsageFlags:
104795c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        if (pCreateInfo->imageUsage != (pCreateInfo->imageUsage & capabilities.supportedUsageFlags)) {
104805c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
104812fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02336, "DS",
104829ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with a non-supported pCreateInfo->imageUsage (i.e. 0x%08x).  Supported flag bits are 0x%08x. %s",
104839ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->imageUsage, capabilities.supportedUsageFlags,
104849ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        validation_error_map[VALIDATION_ERROR_02336]))
104855c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
104865c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
104877de258f87ca1192db116a66b209253793d276ebcChris Forbes    }
10488d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes
104899ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski    // Validate pCreateInfo values with the results of vkGetPhysicalDeviceSurfaceFormatsKHR():
104905faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    if (physical_device_state->vkGetPhysicalDeviceSurfaceFormatsKHRState != QUERY_DETAILS) {
104915faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
104925faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    reinterpret_cast<uint64_t>(dev_data->device), __LINE__, DRAWSTATE_SWAPCHAIN_CREATE_BEFORE_QUERY, "DS",
104939ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    "%s called before calling vkGetPhysicalDeviceSurfaceFormatsKHR().", func_name))
104945faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            return true;
104955faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    } else {
104969ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->imageFormat against VkSurfaceFormatKHR::format:
104975faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        bool foundFormat = false;
104985faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        bool foundColorSpace = false;
104995faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        bool foundMatch = false;
105005faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        for (auto const &format : physical_device_state->surface_formats) {
105015faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            if (pCreateInfo->imageFormat == format.format) {
105029ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                // Validate pCreateInfo->imageColorSpace against VkSurfaceFormatKHR::colorSpace:
105035faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                foundFormat = true;
105045faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                if (pCreateInfo->imageColorSpace == format.colorSpace) {
105055faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    foundMatch = true;
105065faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    break;
105075faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                }
105085faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            } else {
105095faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                if (pCreateInfo->imageColorSpace == format.colorSpace) {
105105faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    foundColorSpace = true;
105115faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                }
105125faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            }
105135faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        }
105145faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        if (!foundMatch) {
105155faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            if (!foundFormat) {
105165faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
105172fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                            reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02333, "DS",
10518bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "%s called with a non-supported pCreateInfo->imageFormat (i.e. %d). %s", func_name,
10519bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            pCreateInfo->imageFormat, validation_error_map[VALIDATION_ERROR_02333]))
105202fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                    return true;
105212fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen            }
105222fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen            if (!foundColorSpace) {
105232fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
105242fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                            reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02333, "DS",
10525bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "%s called with a non-supported pCreateInfo->imageColorSpace (i.e. %d). %s", func_name,
10526bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            pCreateInfo->imageColorSpace, validation_error_map[VALIDATION_ERROR_02333]))
105275faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    return true;
105285faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            }
105295faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        }
105305faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    }
105315faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
105329ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski    // Validate pCreateInfo values with the results of vkGetPhysicalDeviceSurfacePresentModesKHR():
105339e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    if (physical_device_state->vkGetPhysicalDeviceSurfacePresentModesKHRState != QUERY_DETAILS) {
1053425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // FIFO is required to always be supported
105359e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        if (pCreateInfo->presentMode != VK_PRESENT_MODE_FIFO_KHR) {
105369e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
105379ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, DRAWSTATE_SWAPCHAIN_CREATE_BEFORE_QUERY, "DS",
105389ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called before calling vkGetPhysicalDeviceSurfacePresentModesKHR().", func_name))
105399e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                return true;
105409e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
105419e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    } else {
105429ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->presentMode against vkGetPhysicalDeviceSurfacePresentModesKHR():
10543bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        bool foundMatch = std::find(physical_device_state->present_modes.begin(), physical_device_state->present_modes.end(),
105449e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                                    pCreateInfo->presentMode) != physical_device_state->present_modes.end();
105459e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        if (!foundMatch) {
105469e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
105472fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02341, "DS",
105489ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with a non-supported presentMode (i.e. %s). %s", func_name,
105492fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        string_VkPresentModeKHR(pCreateInfo->presentMode), validation_error_map[VALIDATION_ERROR_02341]))
105509e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                return true;
105519e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
105529e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    }
105539e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
10554d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    return false;
10555d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes}
10556d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes
10557261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinskistatic void PostCallRecordCreateSwapchainKHR(layer_data *dev_data, VkResult result, const VkSwapchainCreateInfoKHR *pCreateInfo,
10558261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski                                             VkSwapchainKHR *pSwapchain, SURFACE_STATE *surface_state,
10559261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski                                             SWAPCHAIN_NODE *old_swapchain_state) {
105605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
10561b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
10562ddc5201048319558ce66701163a4546ee957af19Chris Forbes        auto swapchain_state = unique_ptr<SWAPCHAIN_NODE>(new SWAPCHAIN_NODE(pCreateInfo, *pSwapchain));
10563ddc5201048319558ce66701163a4546ee957af19Chris Forbes        surface_state->swapchain = swapchain_state.get();
10564ddc5201048319558ce66701163a4546ee957af19Chris Forbes        dev_data->device_extensions.swapchainMap[*pSwapchain] = std::move(swapchain_state);
10565ddc5201048319558ce66701163a4546ee957af19Chris Forbes    } else {
10566ddc5201048319558ce66701163a4546ee957af19Chris Forbes        surface_state->swapchain = nullptr;
105675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10568ddc5201048319558ce66701163a4546ee957af19Chris Forbes    // Spec requires that even if CreateSwapchainKHR fails, oldSwapchain behaves as replaced.
105695b5488456e5afa0487f95b805a2aba59b13d69f4Chris Forbes    if (old_swapchain_state) {
105705b5488456e5afa0487f95b805a2aba59b13d69f4Chris Forbes        old_swapchain_state->replaced = true;
105715b5488456e5afa0487f95b805a2aba59b13d69f4Chris Forbes    }
10572ddc5201048319558ce66701163a4546ee957af19Chris Forbes    surface_state->old_swapchain = old_swapchain_state;
10573261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski    return;
10574261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski}
10575261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski
10576261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo,
10577261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski                                                  const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchain) {
1057856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
105799a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto surface_state = GetSurfaceState(dev_data->instance_data, pCreateInfo->surface);
105809a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto old_swapchain_state = GetSwapchainNode(dev_data, pCreateInfo->oldSwapchain);
10581261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski
105829ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski    if (PreCallValidateCreateSwapchainKHR(dev_data, "vkCreateSwapChainKHR()", pCreateInfo, surface_state, old_swapchain_state)) {
10583261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski        return VK_ERROR_VALIDATION_FAILED_EXT;
10584261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski    }
10585261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski
10586261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski    VkResult result = dev_data->dispatch_table.CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain);
10587261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski
10588261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski    PostCallRecordCreateSwapchainKHR(dev_data, result, pCreateInfo, pSwapchain, surface_state, old_swapchain_state);
10589ddc5201048319558ce66701163a4546ee957af19Chris Forbes
105905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
105915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
105925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10593bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks *pAllocator) {
1059456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
1059583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
105965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10597b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
105989a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto swapchain_data = GetSwapchainNode(dev_data, swapchain);
10599b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis    if (swapchain_data) {
10600b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis        if (swapchain_data->images.size() > 0) {
10601b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis            for (auto swapchain_image : swapchain_data->images) {
106025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                auto image_sub = dev_data->imageSubresourceMap.find(swapchain_image);
106035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (image_sub != dev_data->imageSubresourceMap.end()) {
106045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    for (auto imgsubpair : image_sub->second) {
106055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        auto image_item = dev_data->imageLayoutMap.find(imgsubpair);
106065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        if (image_item != dev_data->imageLayoutMap.end()) {
106075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                            dev_data->imageLayoutMap.erase(image_item);
106085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        }
106095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
106105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    dev_data->imageSubresourceMap.erase(image_sub);
106115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
1061283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                skip_call =
10613f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                    ClearMemoryObjectBindings(dev_data, (uint64_t)swapchain_image, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT);
1061494c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis                dev_data->imageMap.erase(swapchain_image);
106155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
106165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
10617ddc5201048319558ce66701163a4546ee957af19Chris Forbes
106189a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto surface_state = GetSurfaceState(dev_data->instance_data, swapchain_data->createInfo.surface);
10619ddc5201048319558ce66701163a4546ee957af19Chris Forbes        if (surface_state) {
10620cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (surface_state->swapchain == swapchain_data) surface_state->swapchain = nullptr;
10621cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (surface_state->old_swapchain == swapchain_data) surface_state->old_swapchain = nullptr;
10622ddc5201048319558ce66701163a4546ee957af19Chris Forbes        }
10623ddc5201048319558ce66701163a4546ee957af19Chris Forbes
106245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->device_extensions.swapchainMap.erase(swapchain);
106255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10626b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
10627cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.DestroySwapchainKHR(device, swapchain, pAllocator);
106285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
106295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10630bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pCount,
10631bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                     VkImage *pSwapchainImages) {
1063256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
106334a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.GetSwapchainImagesKHR(device, swapchain, pCount, pSwapchainImages);
106345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
106355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS && pSwapchainImages != NULL) {
106365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // This should never happen and is checked by param checker.
10637cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!pCount) return result;
10638b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
106395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const size_t count = *pCount;
106409a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto swapchain_node = GetSwapchainNode(dev_data, swapchain);
10641b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis        if (swapchain_node && !swapchain_node->images.empty()) {
106420801763633180d277d26a90343464bd11646056fTobin Ehlis            // TODO : Not sure I like the memcmp here, but it works
106430801763633180d277d26a90343464bd11646056fTobin Ehlis            const bool mismatch = (swapchain_node->images.size() != count ||
106440801763633180d277d26a90343464bd11646056fTobin Ehlis                                   memcmp(&swapchain_node->images[0], pSwapchainImages, sizeof(swapchain_node->images[0]) * count));
106455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (mismatch) {
106465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // TODO: Verify against Valid Usage section of extension
106475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
106485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        (uint64_t)swapchain, __LINE__, MEMTRACK_NONE, "SWAP_CHAIN",
10649414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                        "vkGetSwapchainInfoKHR(0x%" PRIx64
106505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        ", VK_SWAP_CHAIN_INFO_TYPE_PERSISTENT_IMAGES_KHR) returned mismatching data",
106515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        (uint64_t)(swapchain));
106525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
106535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
106545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < *pCount; ++i) {
106555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            IMAGE_LAYOUT_NODE image_layout_node;
106565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            image_layout_node.layout = VK_IMAGE_LAYOUT_UNDEFINED;
106575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            image_layout_node.format = swapchain_node->createInfo.imageFormat;
106586d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            // Add imageMap entries for each swapchain image
106596d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            VkImageCreateInfo image_ci = {};
106606d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.mipLevels = 1;
106616d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.arrayLayers = swapchain_node->createInfo.imageArrayLayers;
106626d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.usage = swapchain_node->createInfo.imageUsage;
106636d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.format = swapchain_node->createInfo.imageFormat;
1066441ebcb6b517b1de5ae456d46d866f5e84a96a2c5Tobin Ehlis            image_ci.samples = VK_SAMPLE_COUNT_1_BIT;
106656d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.extent.width = swapchain_node->createInfo.imageExtent.width;
106666d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.extent.height = swapchain_node->createInfo.imageExtent.height;
106676d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.sharingMode = swapchain_node->createInfo.imageSharingMode;
106681facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            dev_data->imageMap[pSwapchainImages[i]] = unique_ptr<IMAGE_STATE>(new IMAGE_STATE(pSwapchainImages[i], &image_ci));
106691facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            auto &image_state = dev_data->imageMap[pSwapchainImages[i]];
106701facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            image_state->valid = false;
10671e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis            image_state->binding.mem = MEMTRACKER_SWAP_CHAIN_IMAGE_KEY;
106725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            swapchain_node->images.push_back(pSwapchainImages[i]);
106735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            ImageSubresourcePair subpair = {pSwapchainImages[i], false, VkImageSubresource()};
106745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->imageSubresourceMap[pSwapchainImages[i]].push_back(subpair);
106755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->imageLayoutMap[subpair] = image_layout_node;
106765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->device_extensions.imageToSwapchainMap[pSwapchainImages[i]] = swapchain;
106775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
106785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
106795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
106805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
106815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1068289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo) {
1068356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
106845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool skip_call = false;
106855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
106866c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    std::lock_guard<std::mutex> lock(global_lock);
106879a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto queue_state = GetQueueState(dev_data, queue);
106881671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes
106896c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    for (uint32_t i = 0; i < pPresentInfo->waitSemaphoreCount; ++i) {
106909a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto pSemaphore = GetSemaphoreNode(dev_data, pPresentInfo->pWaitSemaphores[i]);
106916c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        if (pSemaphore && !pSemaphore->signaled) {
10692226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
10693226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS,
10694226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                 "DS", "Queue 0x%p is waiting on semaphore 0x%" PRIx64 " that has no way to be signaled.", queue,
10695226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                 reinterpret_cast<const uint64_t &>(pPresentInfo->pWaitSemaphores[i]));
106965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
106976c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    }
10698249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis
106996c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    for (uint32_t i = 0; i < pPresentInfo->swapchainCount; ++i) {
107009a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto swapchain_data = GetSwapchainNode(dev_data, pPresentInfo->pSwapchains[i]);
10701a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes        if (swapchain_data) {
10702a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes            if (pPresentInfo->pImageIndices[i] >= swapchain_data->images.size()) {
10703bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                skip_call |= log_msg(
10704bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
10705bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    reinterpret_cast<uint64_t const &>(pPresentInfo->pSwapchains[i]), __LINE__, DRAWSTATE_SWAPCHAIN_INVALID_IMAGE,
10706bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "DS", "vkQueuePresentKHR: Swapchain image index too large (%u). There are only %u images in this swapchain.",
10707bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    pPresentInfo->pImageIndices[i], (uint32_t)swapchain_data->images.size());
10708bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            } else {
10709a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                auto image = swapchain_data->images[pPresentInfo->pImageIndices[i]];
107109a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto image_state = GetImageState(dev_data, image);
107111facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis                skip_call |= ValidateImageMemoryIsValid(dev_data, image_state, "vkQueuePresentKHR()");
10712a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes
107131facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis                if (!image_state->acquired) {
10714bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    skip_call |= log_msg(
10715bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
10716bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        reinterpret_cast<uint64_t const &>(pPresentInfo->pSwapchains[i]), __LINE__,
10717bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        DRAWSTATE_SWAPCHAIN_IMAGE_NOT_ACQUIRED, "DS",
10718bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        "vkQueuePresentKHR: Swapchain image index %u has not been acquired.", pPresentInfo->pImageIndices[i]);
10719a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                }
10720a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes
10721a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                vector<VkImageLayout> layouts;
10722a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                if (FindLayouts(dev_data, image, layouts)) {
10723a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                    for (auto layout : layouts) {
10724a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                        if (layout != VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) {
10725a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                            skip_call |=
107262fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT,
107272fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                        reinterpret_cast<uint64_t &>(queue), __LINE__, VALIDATION_ERROR_01964, "DS",
107282fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                        "Images passed to present must be in layout "
107292fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                        "VK_IMAGE_LAYOUT_PRESENT_SRC_KHR but is in %s. %s",
107302fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                        string_VkImageLayout(layout), validation_error_map[VALIDATION_ERROR_01964]);
10731a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                        }
107325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
107335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
107345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
107351671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes
107361671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            // All physical devices and queue families are required to be able
107371671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            // to present to any native window on Android; require the
107381671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            // application to have established support on any other platform.
107391671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            if (!dev_data->instance_data->androidSurfaceExtensionEnabled) {
107409a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto surface_state = GetSurfaceState(dev_data->instance_data, swapchain_data->createInfo.surface);
107411671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                auto support_it = surface_state->gpu_queue_support.find({dev_data->physical_device, queue_state->queueFamilyIndex});
107421671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes
107431671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                if (support_it == surface_state->gpu_queue_support.end()) {
107441671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                    skip_call |=
107451671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
107461671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                                reinterpret_cast<uint64_t const &>(pPresentInfo->pSwapchains[i]), __LINE__,
10747cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                DRAWSTATE_SWAPCHAIN_UNSUPPORTED_QUEUE, "DS",
10748cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                "vkQueuePresentKHR: Presenting image without calling "
10749cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                "vkGetPhysicalDeviceSurfaceSupportKHR");
107501671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                } else if (!support_it->second) {
10751cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip_call |= log_msg(
10752cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
10753cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        reinterpret_cast<uint64_t const &>(pPresentInfo->pSwapchains[i]), __LINE__, VALIDATION_ERROR_01961, "DS",
10754cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "vkQueuePresentKHR: Presenting image on queue that cannot "
10755cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "present to this surface. %s",
10756cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        validation_error_map[VALIDATION_ERROR_01961]);
107571671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                }
107581671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            }
107595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
107605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
107615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
107626c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    if (skip_call) {
107636c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        return VK_ERROR_VALIDATION_FAILED_EXT;
107646c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    }
107656c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes
107664a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.QueuePresentKHR(queue, pPresentInfo);
107676c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes
107686c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    if (result != VK_ERROR_VALIDATION_FAILED_EXT) {
107696c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        // Semaphore waits occur before error generation, if the call reached
107706c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        // the ICD. (Confirm?)
107716c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        for (uint32_t i = 0; i < pPresentInfo->waitSemaphoreCount; ++i) {
107729a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, pPresentInfo->pWaitSemaphores[i]);
107739867daedbf52debc77d6568162ee21e071699b80Chris Forbes            if (pSemaphore) {
107749867daedbf52debc77d6568162ee21e071699b80Chris Forbes                pSemaphore->signaler.first = VK_NULL_HANDLE;
107756c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes                pSemaphore->signaled = false;
107766c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes            }
107776c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        }
107789867daedbf52debc77d6568162ee21e071699b80Chris Forbes
10779220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes        for (uint32_t i = 0; i < pPresentInfo->swapchainCount; ++i) {
10780220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            // Note: this is imperfect, in that we can get confused about what
10781220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            // did or didn't succeed-- but if the app does that, it's confused
10782220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            // itself just as much.
10783220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            auto local_result = pPresentInfo->pResults ? pPresentInfo->pResults[i] : result;
10784220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes
10785cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (local_result != VK_SUCCESS && local_result != VK_SUBOPTIMAL_KHR) continue;  // this present didn't actually happen.
10786220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes
10787220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            // Mark the image as having been released to the WSI
107889a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto swapchain_data = GetSwapchainNode(dev_data, pPresentInfo->pSwapchains[i]);
10789220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            auto image = swapchain_data->images[pPresentInfo->pImageIndices[i]];
107909a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto image_state = GetImageState(dev_data, image);
107911facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            image_state->acquired = false;
10792220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes        }
10793220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes
107949867daedbf52debc77d6568162ee21e071699b80Chris Forbes        // Note: even though presentation is directed to a queue, there is no
107959867daedbf52debc77d6568162ee21e071699b80Chris Forbes        // direct ordering between QP and subsequent work, so QP (and its
107969867daedbf52debc77d6568162ee21e071699b80Chris Forbes        // semaphore waits) /never/ participate in any completion proof.
107976c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    }
107981344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
107995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
108005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
108015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10802c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinskistatic bool PreCallValidateCreateSharedSwapchainsKHR(layer_data *dev_data, uint32_t swapchainCount,
10803c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                     const VkSwapchainCreateInfoKHR *pCreateInfos, VkSwapchainKHR *pSwapchains,
10804c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                     std::vector<SURFACE_STATE *> &surface_state,
10805c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                     std::vector<SWAPCHAIN_NODE *> &old_swapchain_state) {
108060342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    if (pCreateInfos) {
10807c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski        std::lock_guard<std::mutex> lock(global_lock);
108080342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        for (uint32_t i = 0; i < swapchainCount; i++) {
108099a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            surface_state.push_back(GetSurfaceState(dev_data->instance_data, pCreateInfos[i].surface));
108109a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            old_swapchain_state.push_back(GetSwapchainNode(dev_data, pCreateInfos[i].oldSwapchain));
108119ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            std::stringstream func_name;
108129ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            func_name << "vkCreateSharedSwapchainsKHR[" << swapchainCount << "]";
10813bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (PreCallValidateCreateSwapchainKHR(dev_data, func_name.str().c_str(), &pCreateInfos[i], surface_state[i],
10814bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                  old_swapchain_state[i])) {
10815c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                return true;
108160342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            }
108170342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        }
108180342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    }
10819c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    return false;
10820c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski}
108210342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski
10822c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinskistatic void PostCallRecordCreateSharedSwapchainsKHR(layer_data *dev_data, VkResult result, uint32_t swapchainCount,
10823c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                    const VkSwapchainCreateInfoKHR *pCreateInfos, VkSwapchainKHR *pSwapchains,
10824c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                    std::vector<SURFACE_STATE *> &surface_state,
10825c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                    std::vector<SWAPCHAIN_NODE *> &old_swapchain_state) {
108260342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    if (VK_SUCCESS == result) {
108270342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        for (uint32_t i = 0; i < swapchainCount; i++) {
108280342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            auto swapchain_state = unique_ptr<SWAPCHAIN_NODE>(new SWAPCHAIN_NODE(&pCreateInfos[i], pSwapchains[i]));
108290342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            surface_state[i]->swapchain = swapchain_state.get();
108300342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            dev_data->device_extensions.swapchainMap[pSwapchains[i]] = std::move(swapchain_state);
108310342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        }
108320342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    } else {
108330342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        for (uint32_t i = 0; i < swapchainCount; i++) {
108340342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            surface_state[i]->swapchain = nullptr;
108350342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        }
108360342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    }
108370342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    // Spec requires that even if CreateSharedSwapchainKHR fails, oldSwapchain behaves as replaced.
108380342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    for (uint32_t i = 0; i < swapchainCount; i++) {
108390342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        if (old_swapchain_state[i]) {
108400342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            old_swapchain_state[i]->replaced = true;
108410342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        }
108420342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        surface_state[i]->old_swapchain = old_swapchain_state[i];
108430342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    }
10844c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    return;
10845c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski}
10846c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski
10847c6cd632d064579a64e61d8704b411d0e4ace7adaMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateSharedSwapchainsKHR(VkDevice device, uint32_t swapchainCount,
10848c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                         const VkSwapchainCreateInfoKHR *pCreateInfos,
10849c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                         const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchains) {
1085056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
10851c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    std::vector<SURFACE_STATE *> surface_state;
10852c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    std::vector<SWAPCHAIN_NODE *> old_swapchain_state;
10853c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski
10854c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    if (PreCallValidateCreateSharedSwapchainsKHR(dev_data, swapchainCount, pCreateInfos, pSwapchains, surface_state,
10855c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                 old_swapchain_state)) {
10856c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski        return VK_ERROR_VALIDATION_FAILED_EXT;
10857c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    }
10858c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski
10859c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    VkResult result =
10860c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski        dev_data->dispatch_table.CreateSharedSwapchainsKHR(device, swapchainCount, pCreateInfos, pAllocator, pSwapchains);
10861c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski
10862c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    PostCallRecordCreateSharedSwapchainsKHR(dev_data, result, swapchainCount, pCreateInfos, pSwapchains, surface_state,
10863c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                            old_swapchain_state);
108640342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski
10865c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young    return result;
10866c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young}
10867c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young
1086889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL AcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout,
1086989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                   VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex) {
1087056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
1087183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
108721344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
10873b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
10874449670637ef4214b33018f497cf10daeff9dc85bChris Forbes
10875449670637ef4214b33018f497cf10daeff9dc85bChris Forbes    if (fence == VK_NULL_HANDLE && semaphore == VK_NULL_HANDLE) {
10876449670637ef4214b33018f497cf10daeff9dc85bChris Forbes        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
10877d17d86d15a733f1ec988956721ea4b7cdfb6771bChris Forbes                             reinterpret_cast<uint64_t &>(device), __LINE__, DRAWSTATE_SWAPCHAIN_NO_SYNC_FOR_ACQUIRE, "DS",
10878449670637ef4214b33018f497cf10daeff9dc85bChris Forbes                             "vkAcquireNextImageKHR: Semaphore and fence cannot both be VK_NULL_HANDLE. There would be no way "
10879449670637ef4214b33018f497cf10daeff9dc85bChris Forbes                             "to determine the completion of this operation.");
10880449670637ef4214b33018f497cf10daeff9dc85bChris Forbes    }
10881449670637ef4214b33018f497cf10daeff9dc85bChris Forbes
108829a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
10883f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    if (pSemaphore && pSemaphore->signaled) {
1088483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
108852fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                             reinterpret_cast<const uint64_t &>(semaphore), __LINE__, VALIDATION_ERROR_01952, "DS",
108862fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                             "vkAcquireNextImageKHR: Semaphore must not be currently signaled or in a wait state. %s",
108872fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                             validation_error_map[VALIDATION_ERROR_01952]);
108885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10889f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes
108909a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pFence = GetFenceNode(dev_data, fence);
10891f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    if (pFence) {
1089283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis        skip_call |= ValidateFenceForSubmit(dev_data, pFence);
108935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
108944a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes
108959a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto swapchain_data = GetSwapchainNode(dev_data, swapchain);
10896fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes
10897fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes    if (swapchain_data->replaced) {
10898fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
10899fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes                             reinterpret_cast<uint64_t &>(swapchain), __LINE__, DRAWSTATE_SWAPCHAIN_REPLACED, "DS",
10900fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes                             "vkAcquireNextImageKHR: This swapchain has been replaced. The application can still "
10901fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes                             "present any images it has acquired, but cannot acquire any more.");
10902fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes    }
10903fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes
109049a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(dev_data->instance_data, dev_data->physical_device);
109054a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes    if (physical_device_state->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState != UNCALLED) {
109066569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski        uint64_t acquired_images = std::count_if(swapchain_data->images.begin(), swapchain_data->images.end(),
109079a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                                                 [=](VkImage image) { return GetImageState(dev_data, image)->acquired; });
109084a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes        if (acquired_images > swapchain_data->images.size() - physical_device_state->surfaceCapabilities.minImageCount) {
109096569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski            skip_call |=
109106569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
109116569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski                        reinterpret_cast<uint64_t const &>(swapchain), __LINE__, DRAWSTATE_SWAPCHAIN_TOO_MANY_IMAGES, "DS",
109126569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski                        "vkAcquireNextImageKHR: Application has already acquired the maximum number of images (0x%" PRIxLEAST64 ")",
109136569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski                        acquired_images);
109144a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes        }
109154a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes    }
1091675269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis
1091775269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis    if (swapchain_data->images.size() == 0) {
1091875269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
1091975269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis                             reinterpret_cast<uint64_t const &>(swapchain), __LINE__, DRAWSTATE_SWAPCHAIN_IMAGES_NOT_FOUND, "DS",
1092075269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis                             "vkAcquireNextImageKHR: No images found to acquire from. Application probably did not call "
1092175269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis                             "vkGetSwapchainImagesKHR after swapchain creation.");
1092275269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis    }
1092375269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis
10924b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
109251344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
10926cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
10927f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes
109284a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.AcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, pImageIndex);
10929f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes
10930f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    lock.lock();
10931f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    if (result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR) {
10932f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        if (pFence) {
10933f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes            pFence->state = FENCE_INFLIGHT;
10934cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            pFence->signaler.first = VK_NULL_HANDLE;  // ANI isn't on a queue, so this can't participate in a completion proof.
10935f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        }
10936f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes
10937f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        // A successful call to AcquireNextImageKHR counts as a signal operation on semaphore
10938f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        if (pSemaphore) {
10939f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes            pSemaphore->signaled = true;
109409867daedbf52debc77d6568162ee21e071699b80Chris Forbes            pSemaphore->signaler.first = VK_NULL_HANDLE;
10941f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        }
10942220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes
10943220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes        // Mark the image as acquired.
10944220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes        auto image = swapchain_data->images[*pImageIndex];
109459a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto image_state = GetImageState(dev_data, image);
109461facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        image_state->acquired = true;
109475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10948f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    lock.unlock();
109491344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
109505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
109515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
109525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10953f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount,
10954f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski                                                        VkPhysicalDevice *pPhysicalDevices) {
1095583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
1095656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
10957bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    assert(instance_data);
10958219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes
10959bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    // For this instance, flag when vkEnumeratePhysicalDevices goes to QUERY_COUNT and then QUERY_DETAILS
10960bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    if (NULL == pPhysicalDevices) {
10961bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        instance_data->vkEnumeratePhysicalDevicesState = QUERY_COUNT;
10962f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    } else {
10963bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        if (UNCALLED == instance_data->vkEnumeratePhysicalDevicesState) {
10964bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            // Flag warning here. You can call this without having queried the count, but it may not be
10965bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            // robust on platforms with multiple physical devices.
10966bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            skip_call |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
10967bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis                                 VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, 0, __LINE__, DEVLIMITS_MISSING_QUERY_COUNT, "DL",
10968bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis                                 "Call sequence has vkEnumeratePhysicalDevices() w/ non-NULL pPhysicalDevices. You should first "
10969bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis                                 "call vkEnumeratePhysicalDevices() w/ NULL pPhysicalDevices to query pPhysicalDeviceCount.");
10970cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }  // TODO : Could also flag a warning if re-calling this function in QUERY_DETAILS state
10971bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        else if (instance_data->physical_devices_count != *pPhysicalDeviceCount) {
10972bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            // Having actual count match count from app is not a requirement, so this can be a warning
10973bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            skip_call |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
10974bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis                                 VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVLIMITS_COUNT_MISMATCH, "DL",
10975bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis                                 "Call to vkEnumeratePhysicalDevices() w/ pPhysicalDeviceCount value %u, but actual count "
10976bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis                                 "supported by this instance is %u.",
10977bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis                                 *pPhysicalDeviceCount, instance_data->physical_devices_count);
10978bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        }
10979bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        instance_data->vkEnumeratePhysicalDevicesState = QUERY_DETAILS;
10980f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    }
10981bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    if (skip_call) {
10982bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        return VK_ERROR_VALIDATION_FAILED_EXT;
10983bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    }
10984bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    VkResult result = instance_data->dispatch_table.EnumeratePhysicalDevices(instance, pPhysicalDeviceCount, pPhysicalDevices);
10985bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    if (NULL == pPhysicalDevices) {
10986bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        instance_data->physical_devices_count = *pPhysicalDeviceCount;
10987cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    } else if (result == VK_SUCCESS) {  // Save physical devices
10988bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        for (uint32_t i = 0; i < *pPhysicalDeviceCount; i++) {
10989bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            auto &phys_device_state = instance_data->physical_device_map[pPhysicalDevices[i]];
10990bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            phys_device_state.phys_device = pPhysicalDevices[i];
10991bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            // Init actual features for each physical device
10992bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            instance_data->dispatch_table.GetPhysicalDeviceFeatures(pPhysicalDevices[i], &phys_device_state.features);
10993bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        }
10994bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    }
10995bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    return result;
10996f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski}
10997f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
1099843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis// Common function to handle validation for GetPhysicalDeviceQueueFamilyProperties & 2KHR version
1099943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic bool ValidateCommonGetPhysicalDeviceQueueFamilyProperties(instance_layer_data *instance_data,
1100043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                 PHYSICAL_DEVICE_STATE *pd_state,
1100143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                 uint32_t *pQueueFamilyPropertyCount, bool qfp_null,
1100243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                 const char *count_var_name, const char *caller_name) {
1100343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    bool skip = false;
1100443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    if (qfp_null) {
1100543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        pd_state->vkGetPhysicalDeviceQueueFamilyPropertiesState = QUERY_COUNT;
1100643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    } else {
1100743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        // Verify that for each physical device, this function is called first with NULL pQueueFamilyProperties ptr in order to get
1100843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        // count
1100943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        if (UNCALLED == pd_state->vkGetPhysicalDeviceQueueFamilyPropertiesState) {
1101043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
1101143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                            VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVLIMITS_MISSING_QUERY_COUNT, "DL",
1101243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                            "Call sequence has %s() w/ non-NULL "
1101343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                            "pQueueFamilyProperties. You should first call %s() w/ "
1101443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                            "NULL pQueueFamilyProperties to query pCount.",
1101543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                            caller_name, caller_name);
1101643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        }
1101743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        // Then verify that pCount that is passed in on second call matches what was returned
1101843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        if (pd_state->queueFamilyPropertiesCount != *pQueueFamilyPropertyCount) {
1101943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            // TODO: this is not a requirement of the Valid Usage section for vkGetPhysicalDeviceQueueFamilyProperties, so
1102043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            // provide as warning
1102143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
1102243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                            VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVLIMITS_COUNT_MISMATCH, "DL",
1102343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                            "Call to %s() w/ %s value %u, but actual count supported by this physicalDevice is %u.", caller_name,
1102443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                            count_var_name, *pQueueFamilyPropertyCount, pd_state->queueFamilyPropertiesCount);
1102543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        }
1102643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        pd_state->vkGetPhysicalDeviceQueueFamilyPropertiesState = QUERY_DETAILS;
1102743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    }
1102843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    return skip;
1102943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1103043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1103143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic bool PreCallValidateGetPhysicalDeviceQueueFamilyProperties(instance_layer_data *instance_data,
1103243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                  PHYSICAL_DEVICE_STATE *pd_state, uint32_t *pCount,
1103343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                  VkQueueFamilyProperties *pQueueFamilyProperties) {
1103443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    return ValidateCommonGetPhysicalDeviceQueueFamilyProperties(instance_data, pd_state, pCount,
1103543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                (nullptr == pQueueFamilyProperties), "pCount",
1103643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                "vkGetPhysicalDeviceQueueFamilyProperties()");
1103743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1103843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1103943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic bool PreCallValidateGetPhysicalDeviceQueueFamilyProperties2KHR(instance_layer_data *instance_data,
1104043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                      PHYSICAL_DEVICE_STATE *pd_state,
1104143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                      uint32_t *pQueueFamilyPropertyCount,
1104243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                      VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
1104343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    return ValidateCommonGetPhysicalDeviceQueueFamilyProperties(instance_data, pd_state, pQueueFamilyPropertyCount,
1104443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                (nullptr == pQueueFamilyProperties), "pQueueFamilyPropertyCount",
1104543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                "vkGetPhysicalDeviceQueueFamilyProperties2KHR()");
1104643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1104743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1104843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis// Common function to update state for GetPhysicalDeviceQueueFamilyProperties & 2KHR version
1104943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic void StateUpdateCommonGetPhysicalDeviceQueueFamilyProperties(PHYSICAL_DEVICE_STATE *pd_state, uint32_t count,
1105043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                    VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
1105143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    if (!pQueueFamilyProperties) {
1105243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        pd_state->queueFamilyPropertiesCount = count;
1105343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    } else {  // Save queue family properties
1105443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        if (pd_state->queue_family_properties.size() < count) pd_state->queue_family_properties.resize(count);
1105543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        for (uint32_t i = 0; i < count; i++) {
1105643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            pd_state->queue_family_properties[i] = pQueueFamilyProperties[i].queueFamilyProperties;
1105743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        }
1105843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    }
1105943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1106043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1106143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic void PostCallRecordGetPhysicalDeviceQueueFamilyProperties(PHYSICAL_DEVICE_STATE *pd_state, uint32_t count,
1106243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                 VkQueueFamilyProperties *pQueueFamilyProperties) {
1106343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    VkQueueFamilyProperties2KHR *pqfp = nullptr;
1106443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    std::vector<VkQueueFamilyProperties2KHR> qfp;
1106543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    qfp.resize(count);
1106643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    if (pQueueFamilyProperties) {
1106743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        for (uint32_t i = 0; i < count; ++i) {
1106843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            qfp[i].sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR;
1106943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            qfp[i].pNext = nullptr;
1107043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            qfp[i].queueFamilyProperties = pQueueFamilyProperties[i];
1107143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        }
1107243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        pqfp = qfp.data();
1107343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    }
1107443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    StateUpdateCommonGetPhysicalDeviceQueueFamilyProperties(pd_state, count, pqfp);
1107543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1107643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1107743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic void PostCallRecordGetPhysicalDeviceQueueFamilyProperties2KHR(PHYSICAL_DEVICE_STATE *pd_state, uint32_t count,
1107843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                     VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
1107943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    StateUpdateCommonGetPhysicalDeviceQueueFamilyProperties(pd_state, count, pQueueFamilyProperties);
1108043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1108143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
11082bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
11083bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                  VkQueueFamilyProperties *pQueueFamilyProperties) {
1108456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
110859a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
1108643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    assert(physical_device_state);
1108743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    bool skip =
1108843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        PreCallValidateGetPhysicalDeviceQueueFamilyProperties(instance_data, physical_device_state, pCount, pQueueFamilyProperties);
1108943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    if (skip) {
1109043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        return;
1109143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    }
1109243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, pCount, pQueueFamilyProperties);
1109343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    PostCallRecordGetPhysicalDeviceQueueFamilyProperties(physical_device_state, *pCount, pQueueFamilyProperties);
1109443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1109543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1109643947a6175e3e942e04d902f4d18928168e2d0dbTobin EhlisVKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceQueueFamilyProperties2KHR(VkPhysicalDevice physicalDevice,
1109743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                      uint32_t *pQueueFamilyPropertyCount,
1109843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                      VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
1109956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
111009a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
1110143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    assert(physical_device_state);
1110243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    bool skip = PreCallValidateGetPhysicalDeviceQueueFamilyProperties2KHR(instance_data, physical_device_state,
1110343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                          pQueueFamilyPropertyCount, pQueueFamilyProperties);
1110443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    if (skip) {
1110543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        return;
11106cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski    }
1110743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties2KHR(physicalDevice, pQueueFamilyPropertyCount,
1110843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                             pQueueFamilyProperties);
1110943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    PostCallRecordGetPhysicalDeviceQueueFamilyProperties2KHR(physical_device_state, *pQueueFamilyPropertyCount,
1111043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                             pQueueFamilyProperties);
11111cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski}
11112cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski
11113bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskitemplate <typename TCreateInfo, typename FPtr>
11114bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic VkResult CreateSurface(VkInstance instance, TCreateInfo const *pCreateInfo, VkAllocationCallbacks const *pAllocator,
11115bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                              VkSurfaceKHR *pSurface, FPtr fptr) {
1111656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
11117747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11118747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    // Call down the call chain:
11119747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    VkResult result = (instance_data->dispatch_table.*fptr)(instance, pCreateInfo, pAllocator, pSurface);
11120747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11121747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    if (result == VK_SUCCESS) {
11122747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        std::unique_lock<std::mutex> lock(global_lock);
11123747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        instance_data->surface_map[*pSurface] = SURFACE_STATE(*pSurface);
11124747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        lock.unlock();
11125747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
11126747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11127747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return result;
11128747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11129747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11130747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR void VKAPI_CALL DestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks *pAllocator) {
11131747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool skip_call = false;
1113256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
11133747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
111349a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto surface_state = GetSurfaceState(instance_data, surface);
11135747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11136747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    if (surface_state) {
11137747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        // TODO: track swapchains created from this surface.
11138747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        instance_data->surface_map.erase(surface);
11139747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
11140747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    lock.unlock();
11141747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11142747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    if (!skip_call) {
11143747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        // Call down the call chain:
11144747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        instance_data->dispatch_table.DestroySurfaceKHR(instance, surface, pAllocator);
11145747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
11146747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11147747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
111486f2ed666809272002a31b3b4f8adf6581cb41819Norbert NopperVKAPI_ATTR VkResult VKAPI_CALL CreateDisplayPlaneSurfaceKHR(VkInstance instance, const VkDisplaySurfaceCreateInfoKHR *pCreateInfo,
111496f2ed666809272002a31b3b4f8adf6581cb41819Norbert Nopper                                                            const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
111506f2ed666809272002a31b3b4f8adf6581cb41819Norbert Nopper    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateDisplayPlaneSurfaceKHR);
111516f2ed666809272002a31b3b4f8adf6581cb41819Norbert Nopper}
111526f2ed666809272002a31b3b4f8adf6581cb41819Norbert Nopper
11153747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_ANDROID_KHR
11154747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR *pCreateInfo,
11155747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                       const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
11156747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateAndroidSurfaceKHR);
11157747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11158cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_ANDROID_KHR
11159747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11160747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_MIR_KHR
11161747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateMirSurfaceKHR(VkInstance instance, const VkMirSurfaceCreateInfoKHR *pCreateInfo,
11162747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                   const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
11163747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateMirSurfaceKHR);
11164747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11165cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_MIR_KHR
11166747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11167747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WAYLAND_KHR
11168747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateWaylandSurfaceKHR(VkInstance instance, const VkWaylandSurfaceCreateInfoKHR *pCreateInfo,
11169747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                       const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
11170a9c6cc532ce0ef61d48d1419a96aae51b0e4c64aTobin Ehlis    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateWaylandSurfaceKHR);
11171747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11172cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_WAYLAND_KHR
11173747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11174747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WIN32_KHR
11175747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateWin32SurfaceKHR(VkInstance instance, const VkWin32SurfaceCreateInfoKHR *pCreateInfo,
11176747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                     const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
11177747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateWin32SurfaceKHR);
11178747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11179cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_WIN32_KHR
11180747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11181747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XCB_KHR
11182747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateXcbSurfaceKHR(VkInstance instance, const VkXcbSurfaceCreateInfoKHR *pCreateInfo,
11183747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                   const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
11184747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateXcbSurfaceKHR);
11185747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11186cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_XCB_KHR
11187747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11188747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XLIB_KHR
11189747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateXlibSurfaceKHR(VkInstance instance, const VkXlibSurfaceCreateInfoKHR *pCreateInfo,
11190bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                    const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
11191747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateXlibSurfaceKHR);
11192747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11193cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_XLIB_KHR
11194747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
1119540921785005eb449ec7c18229f0d84c879708b8aChris ForbesVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
1119640921785005eb449ec7c18229f0d84c879708b8aChris Forbes                                                                       VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) {
1119756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    auto instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
1119840921785005eb449ec7c18229f0d84c879708b8aChris Forbes
1119940921785005eb449ec7c18229f0d84c879708b8aChris Forbes    std::unique_lock<std::mutex> lock(global_lock);
112009a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
1120140921785005eb449ec7c18229f0d84c879708b8aChris Forbes    lock.unlock();
1120240921785005eb449ec7c18229f0d84c879708b8aChris Forbes
11203bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result =
11204bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        instance_data->dispatch_table.GetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, pSurfaceCapabilities);
1120540921785005eb449ec7c18229f0d84c879708b8aChris Forbes
1120640921785005eb449ec7c18229f0d84c879708b8aChris Forbes    if (result == VK_SUCCESS) {
1120740921785005eb449ec7c18229f0d84c879708b8aChris Forbes        physical_device_state->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState = QUERY_DETAILS;
1120840921785005eb449ec7c18229f0d84c879708b8aChris Forbes        physical_device_state->surfaceCapabilities = *pSurfaceCapabilities;
1120940921785005eb449ec7c18229f0d84c879708b8aChris Forbes    }
1121040921785005eb449ec7c18229f0d84c879708b8aChris Forbes
1121140921785005eb449ec7c18229f0d84c879708b8aChris Forbes    return result;
1121240921785005eb449ec7c18229f0d84c879708b8aChris Forbes}
1121340921785005eb449ec7c18229f0d84c879708b8aChris Forbes
11214418a8711f3301f3027a900bb45daaf0892f4e644Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex,
11215418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes                                                                  VkSurfaceKHR surface, VkBool32 *pSupported) {
1121656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    auto instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
11217418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
112189a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto surface_state = GetSurfaceState(instance_data, surface);
11219418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    lock.unlock();
11220418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes
11221bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result =
11222bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        instance_data->dispatch_table.GetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, surface, pSupported);
11223418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes
11224418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    if (result == VK_SUCCESS) {
112256569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski        surface_state->gpu_queue_support[{physicalDevice, queueFamilyIndex}] = (*pSupported != 0);
11226418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    }
11227418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes
11228418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    return result;
11229418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes}
11230418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes
112319e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
112329e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                                                                       uint32_t *pPresentModeCount,
112339e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                                                                       VkPresentModeKHR *pPresentModes) {
112349e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    bool skip_call = false;
1123556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    auto instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
112369e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
112379e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    // TODO: this isn't quite right. available modes may differ by surface AND physical device.
112389a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
11239bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto &call_state = physical_device_state->vkGetPhysicalDeviceSurfacePresentModesKHRState;
112409e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
112419e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    if (pPresentModes) {
112429e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        // Compare the preliminary value of *pPresentModeCount with the value this time:
11243bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto prev_mode_count = (uint32_t)physical_device_state->present_modes.size();
112449e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        switch (call_state) {
11245cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case UNCALLED:
112469e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                skip_call |= log_msg(
11247bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
11248cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    reinterpret_cast<uint64_t>(physicalDevice), __LINE__, DEVLIMITS_MUST_QUERY_COUNT, "DL",
11249cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "vkGetPhysicalDeviceSurfacePresentModesKHR() called with non-NULL pPresentModeCount; but no prior positive "
11250cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "value has been seen for pPresentModeCount.");
11251cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
11252cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
11253cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // both query count and query details
11254cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (*pPresentModeCount != prev_mode_count) {
11255cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip_call |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
11256cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
11257cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         reinterpret_cast<uint64_t>(physicalDevice), __LINE__, DEVLIMITS_COUNT_MISMATCH, "DL",
11258cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         "vkGetPhysicalDeviceSurfacePresentModesKHR() called with *pPresentModeCount (%u) that "
11259cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         "differs from the value "
11260cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         "(%u) that was returned when pPresentModes was NULL.",
11261cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         *pPresentModeCount, prev_mode_count);
11262cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
11263cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
112649e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
112659e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    }
112669e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    lock.unlock();
112679e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
11268cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
112699e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
11270bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result = instance_data->dispatch_table.GetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, pPresentModeCount,
11271bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                        pPresentModes);
112729e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
112739e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
112749e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        lock.lock();
112759e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
112769e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        if (*pPresentModeCount) {
11277cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (call_state < QUERY_COUNT) call_state = QUERY_COUNT;
112789e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            if (*pPresentModeCount > physical_device_state->present_modes.size())
112799e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                physical_device_state->present_modes.resize(*pPresentModeCount);
112809e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
112819e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        if (pPresentModes) {
11282cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (call_state < QUERY_DETAILS) call_state = QUERY_DETAILS;
112839e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            for (uint32_t i = 0; i < *pPresentModeCount; i++) {
112849e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                physical_device_state->present_modes[i] = pPresentModes[i];
112859e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            }
112869e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
112875faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    }
112885faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
112895faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    return result;
112905faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes}
112915faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
112925faa662f6859b01c72d79027abde363d5f10dcd7Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
112935faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                                                                  uint32_t *pSurfaceFormatCount,
112945faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                                                                  VkSurfaceFormatKHR *pSurfaceFormats) {
112955faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    bool skip_call = false;
1129656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    auto instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
112975faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
112989a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
11299bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto &call_state = physical_device_state->vkGetPhysicalDeviceSurfaceFormatsKHRState;
113005faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
113015faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    if (pSurfaceFormats) {
11302bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto prev_format_count = (uint32_t)physical_device_state->surface_formats.size();
113035faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
113045faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        switch (call_state) {
11305cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case UNCALLED:
11306cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // Since we haven't recorded a preliminary value of *pSurfaceFormatCount, that likely means that the application
11307cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // didn't
11308cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // previously call this function with a NULL value of pSurfaceFormats:
113095faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                skip_call |= log_msg(
11310bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
11311cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    reinterpret_cast<uint64_t>(physicalDevice), __LINE__, DEVLIMITS_MUST_QUERY_COUNT, "DL",
11312cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "vkGetPhysicalDeviceSurfaceFormatsKHR() called with non-NULL pSurfaceFormatCount; but no prior positive "
11313cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "value has been seen for pSurfaceFormats.");
11314cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
11315cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
11316cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (prev_format_count != *pSurfaceFormatCount) {
11317cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip_call |= log_msg(
11318cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
11319cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, reinterpret_cast<uint64_t>(physicalDevice), __LINE__,
11320cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        DEVLIMITS_COUNT_MISMATCH, "DL",
11321cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "vkGetPhysicalDeviceSurfaceFormatsKHR() called with non-NULL pSurfaceFormatCount, and with pSurfaceFormats "
11322cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "set "
11323cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "to "
11324cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "a value (%u) that is greater than the value (%u) that was returned when pSurfaceFormatCount was NULL.",
11325cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        *pSurfaceFormatCount, prev_format_count);
11326cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
11327cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
113289e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
113299e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    }
113305faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    lock.unlock();
113315faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
11332cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
113339e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
113345faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    // Call down the call chain:
113355faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    auto result = instance_data->dispatch_table.GetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, pSurfaceFormatCount,
113365faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                                                                                   pSurfaceFormats);
113375faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
113385faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
113395faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        lock.lock();
113405faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
113415faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        if (*pSurfaceFormatCount) {
11342cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (call_state < QUERY_COUNT) call_state = QUERY_COUNT;
113435faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            if (*pSurfaceFormatCount > physical_device_state->surface_formats.size())
113445faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                physical_device_state->surface_formats.resize(*pSurfaceFormatCount);
113455faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        }
113465faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        if (pSurfaceFormats) {
11347cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (call_state < QUERY_DETAILS) call_state = QUERY_DETAILS;
113485faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            for (uint32_t i = 0; i < *pSurfaceFormatCount; i++) {
113495faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                physical_device_state->surface_formats[i] = pSurfaceFormats[i];
113505faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            }
113515faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        }
113525faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    }
113539e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    return result;
113549e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes}
113559e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
11356bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateDebugReportCallbackEXT(VkInstance instance,
11357bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                            const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
11358bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                            const VkAllocationCallbacks *pAllocator,
11359bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                            VkDebugReportCallbackEXT *pMsgCallback) {
1136056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
113619172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    VkResult res = instance_data->dispatch_table.CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
113625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == res) {
11363b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
113648860b85a52096f9f9b28616bc37feed505497a54Chris Forbes        res = layer_create_msg_callback(instance_data->report_data, false, pCreateInfo, pAllocator, pMsgCallback);
113655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
113665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return res;
113675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
113685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11369bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT msgCallback,
1137089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                         const VkAllocationCallbacks *pAllocator) {
1137156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
113729172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    instance_data->dispatch_table.DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);
11373b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::lock_guard<std::mutex> lock(global_lock);
113748860b85a52096f9f9b28616bc37feed505497a54Chris Forbes    layer_destroy_msg_callback(instance_data->report_data, msgCallback, pAllocator);
113755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
113765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11377bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags,
11378bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 VkDebugReportObjectTypeEXT objType, uint64_t object, size_t location,
11379bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
1138056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
113819172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    instance_data->dispatch_table.DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, pMsg);
113825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
113835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11384bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties) {
11385a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return util_GetLayerProperties(1, &global_layer, pCount, pProperties);
11386a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu}
11387a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu
11388bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
11389bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                              VkLayerProperties *pProperties) {
11390a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return util_GetLayerProperties(1, &global_layer, pCount, pProperties);
11391a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu}
11392a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu
11393bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
11394bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                    VkExtensionProperties *pProperties) {
11395a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    if (pLayerName && !strcmp(pLayerName, global_layer.layerName))
11396a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu        return util_GetExtensionProperties(1, instance_extensions, pCount, pProperties);
11397a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu
11398a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return VK_ERROR_LAYER_NOT_PRESENT;
11399a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu}
11400a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu
11401bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char *pLayerName,
11402bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                  uint32_t *pCount, VkExtensionProperties *pProperties) {
11403cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (pLayerName && !strcmp(pLayerName, global_layer.layerName)) return util_GetExtensionProperties(0, NULL, pCount, pProperties);
11404a8f4a23b1e9c068717eda47cc583a93f447c77e3Chia-I Wu
11405a8f4a23b1e9c068717eda47cc583a93f447c77e3Chia-I Wu    assert(physicalDevice);
11406a8f4a23b1e9c068717eda47cc583a93f447c77e3Chia-I Wu
1140756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
114089172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    return instance_data->dispatch_table.EnumerateDeviceExtensionProperties(physicalDevice, NULL, pCount, pProperties);
1140908939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu}
1141008939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu
11411bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_core_instance_command(const char *name);
114127ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu
11413bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_core_device_command(const char *name);
1141480be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu
11415bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_khr_swapchain_command(const char *name, VkDevice dev);
1141609a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu
11417bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_khr_surface_command(const char *name, VkInstance instance);
11418747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11419bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_extension_instance_commands(const char *name, VkInstance instance);
11420b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
1142189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice dev, const char *funcName) {
1142280be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    PFN_vkVoidFunction proc = intercept_core_device_command(funcName);
11423cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (proc) return proc;
1142480be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu
1142580be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    assert(dev);
114265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1142709a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu    proc = intercept_khr_swapchain_command(funcName, dev);
11428cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (proc) return proc;
1142909a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu
1143056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(dev), layer_data_map);
114315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
114324a0754042cf090e131e9e769d8a3633c228625beChris Forbes    auto &table = dev_data->dispatch_table;
11433cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!table.GetDeviceProcAddr) return nullptr;
114344a0754042cf090e131e9e769d8a3633c228625beChris Forbes    return table.GetDeviceProcAddr(dev, funcName);
114355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
114365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1143789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetInstanceProcAddr(VkInstance instance, const char *funcName) {
114387ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    PFN_vkVoidFunction proc = intercept_core_instance_command(funcName);
11439cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!proc) proc = intercept_core_device_command(funcName);
11440cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!proc) proc = intercept_khr_swapchain_command(funcName, VK_NULL_HANDLE);
11441cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!proc) proc = intercept_khr_surface_command(funcName, instance);
11442cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (proc) return proc;
114435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
114447ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    assert(instance);
114455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1144656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
114478860b85a52096f9f9b28616bc37feed505497a54Chris Forbes    proc = debug_report_get_instance_proc_addr(instance_data->report_data, funcName);
11448cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (proc) return proc;
114495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11450b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    proc = intercept_extension_instance_commands(funcName, instance);
11451cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (proc) return proc;
11452b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
114534a0754042cf090e131e9e769d8a3633c228625beChris Forbes    auto &table = instance_data->dispatch_table;
11454cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!table.GetInstanceProcAddr) return nullptr;
114554a0754042cf090e131e9e769d8a3633c228625beChris Forbes    return table.GetInstanceProcAddr(instance, funcName);
114565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
1145708939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu
11458b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark YoungVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
11459b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    assert(instance);
11460b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
1146156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
11462b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11463b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    auto &table = instance_data->dispatch_table;
11464cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!table.GetPhysicalDeviceProcAddr) return nullptr;
11465b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    return table.GetPhysicalDeviceProcAddr(instance, funcName);
11466b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young}
11467b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11468bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_core_instance_command(const char *name) {
114697ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    static const struct {
114707ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu        const char *name;
114717ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu        PFN_vkVoidFunction proc;
114727ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    } core_instance_commands[] = {
11473bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkGetInstanceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetInstanceProcAddr)},
11474bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vk_layerGetPhysicalDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceProcAddr)},
11475bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkGetDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceProcAddr)},
11476bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkCreateInstance", reinterpret_cast<PFN_vkVoidFunction>(CreateInstance)},
11477bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkCreateDevice", reinterpret_cast<PFN_vkVoidFunction>(CreateDevice)},
11478bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkEnumeratePhysicalDevices", reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDevices)},
11479bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkGetPhysicalDeviceQueueFamilyProperties", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceQueueFamilyProperties)},
11480bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkDestroyInstance", reinterpret_cast<PFN_vkVoidFunction>(DestroyInstance)},
11481bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkEnumerateInstanceLayerProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceLayerProperties)},
11482bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkEnumerateDeviceLayerProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateDeviceLayerProperties)},
11483bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkEnumerateInstanceExtensionProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceExtensionProperties)},
11484bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkEnumerateDeviceExtensionProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateDeviceExtensionProperties)},
114857ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    };
114867ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu
114877ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    for (size_t i = 0; i < ARRAY_SIZE(core_instance_commands); i++) {
11488cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!strcmp(core_instance_commands[i].name, name)) return core_instance_commands[i].proc;
114897ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    }
114907ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu
114917ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    return nullptr;
114927ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu}
114937ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu
11494bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_core_device_command(const char *name) {
1149580be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    static const struct {
1149680be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu        const char *name;
1149780be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu        PFN_vkVoidFunction proc;
1149880be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    } core_device_commands[] = {
11499593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkGetDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceProcAddr)},
11500593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkQueueSubmit", reinterpret_cast<PFN_vkVoidFunction>(QueueSubmit)},
11501593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkWaitForFences", reinterpret_cast<PFN_vkVoidFunction>(WaitForFences)},
11502593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkGetFenceStatus", reinterpret_cast<PFN_vkVoidFunction>(GetFenceStatus)},
11503593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkQueueWaitIdle", reinterpret_cast<PFN_vkVoidFunction>(QueueWaitIdle)},
11504593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDeviceWaitIdle", reinterpret_cast<PFN_vkVoidFunction>(DeviceWaitIdle)},
11505593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkGetDeviceQueue", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceQueue)},
11506593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyInstance", reinterpret_cast<PFN_vkVoidFunction>(DestroyInstance)},
11507593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyDevice", reinterpret_cast<PFN_vkVoidFunction>(DestroyDevice)},
11508593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyFence", reinterpret_cast<PFN_vkVoidFunction>(DestroyFence)},
11509593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkResetFences", reinterpret_cast<PFN_vkVoidFunction>(ResetFences)},
11510593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroySemaphore", reinterpret_cast<PFN_vkVoidFunction>(DestroySemaphore)},
11511593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyEvent", reinterpret_cast<PFN_vkVoidFunction>(DestroyEvent)},
11512593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyQueryPool", reinterpret_cast<PFN_vkVoidFunction>(DestroyQueryPool)},
11513593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyBuffer", reinterpret_cast<PFN_vkVoidFunction>(DestroyBuffer)},
11514593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyBufferView", reinterpret_cast<PFN_vkVoidFunction>(DestroyBufferView)},
11515593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyImage", reinterpret_cast<PFN_vkVoidFunction>(DestroyImage)},
11516593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyImageView", reinterpret_cast<PFN_vkVoidFunction>(DestroyImageView)},
11517593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyShaderModule", reinterpret_cast<PFN_vkVoidFunction>(DestroyShaderModule)},
11518593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyPipeline", reinterpret_cast<PFN_vkVoidFunction>(DestroyPipeline)},
11519593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyPipelineLayout", reinterpret_cast<PFN_vkVoidFunction>(DestroyPipelineLayout)},
11520593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroySampler", reinterpret_cast<PFN_vkVoidFunction>(DestroySampler)},
11521593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyDescriptorSetLayout", reinterpret_cast<PFN_vkVoidFunction>(DestroyDescriptorSetLayout)},
11522593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(DestroyDescriptorPool)},
11523593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyFramebuffer", reinterpret_cast<PFN_vkVoidFunction>(DestroyFramebuffer)},
11524593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyRenderPass", reinterpret_cast<PFN_vkVoidFunction>(DestroyRenderPass)},
11525593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateBuffer", reinterpret_cast<PFN_vkVoidFunction>(CreateBuffer)},
11526593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateBufferView", reinterpret_cast<PFN_vkVoidFunction>(CreateBufferView)},
11527593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateImage", reinterpret_cast<PFN_vkVoidFunction>(CreateImage)},
11528593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateImageView", reinterpret_cast<PFN_vkVoidFunction>(CreateImageView)},
11529593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateFence", reinterpret_cast<PFN_vkVoidFunction>(CreateFence)},
11530593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreatePipelineCache", reinterpret_cast<PFN_vkVoidFunction>(CreatePipelineCache)},
11531593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyPipelineCache", reinterpret_cast<PFN_vkVoidFunction>(DestroyPipelineCache)},
11532593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkGetPipelineCacheData", reinterpret_cast<PFN_vkVoidFunction>(GetPipelineCacheData)},
11533593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkMergePipelineCaches", reinterpret_cast<PFN_vkVoidFunction>(MergePipelineCaches)},
11534593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateGraphicsPipelines", reinterpret_cast<PFN_vkVoidFunction>(CreateGraphicsPipelines)},
11535593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateComputePipelines", reinterpret_cast<PFN_vkVoidFunction>(CreateComputePipelines)},
11536593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateSampler", reinterpret_cast<PFN_vkVoidFunction>(CreateSampler)},
11537593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateDescriptorSetLayout", reinterpret_cast<PFN_vkVoidFunction>(CreateDescriptorSetLayout)},
11538593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreatePipelineLayout", reinterpret_cast<PFN_vkVoidFunction>(CreatePipelineLayout)},
11539593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(CreateDescriptorPool)},
11540593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkResetDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(ResetDescriptorPool)},
11541593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkAllocateDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(AllocateDescriptorSets)},
11542593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkFreeDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(FreeDescriptorSets)},
11543593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkUpdateDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(UpdateDescriptorSets)},
11544593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateCommandPool", reinterpret_cast<PFN_vkVoidFunction>(CreateCommandPool)},
11545593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyCommandPool", reinterpret_cast<PFN_vkVoidFunction>(DestroyCommandPool)},
11546593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkResetCommandPool", reinterpret_cast<PFN_vkVoidFunction>(ResetCommandPool)},
11547593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateQueryPool", reinterpret_cast<PFN_vkVoidFunction>(CreateQueryPool)},
11548593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkAllocateCommandBuffers", reinterpret_cast<PFN_vkVoidFunction>(AllocateCommandBuffers)},
11549593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkFreeCommandBuffers", reinterpret_cast<PFN_vkVoidFunction>(FreeCommandBuffers)},
11550593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkBeginCommandBuffer", reinterpret_cast<PFN_vkVoidFunction>(BeginCommandBuffer)},
11551593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkEndCommandBuffer", reinterpret_cast<PFN_vkVoidFunction>(EndCommandBuffer)},
11552593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkResetCommandBuffer", reinterpret_cast<PFN_vkVoidFunction>(ResetCommandBuffer)},
11553593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdBindPipeline", reinterpret_cast<PFN_vkVoidFunction>(CmdBindPipeline)},
11554593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetViewport", reinterpret_cast<PFN_vkVoidFunction>(CmdSetViewport)},
11555593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetScissor", reinterpret_cast<PFN_vkVoidFunction>(CmdSetScissor)},
11556593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetLineWidth", reinterpret_cast<PFN_vkVoidFunction>(CmdSetLineWidth)},
11557593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetDepthBias", reinterpret_cast<PFN_vkVoidFunction>(CmdSetDepthBias)},
11558593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetBlendConstants", reinterpret_cast<PFN_vkVoidFunction>(CmdSetBlendConstants)},
11559593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetDepthBounds", reinterpret_cast<PFN_vkVoidFunction>(CmdSetDepthBounds)},
11560593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetStencilCompareMask", reinterpret_cast<PFN_vkVoidFunction>(CmdSetStencilCompareMask)},
11561593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetStencilWriteMask", reinterpret_cast<PFN_vkVoidFunction>(CmdSetStencilWriteMask)},
11562593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetStencilReference", reinterpret_cast<PFN_vkVoidFunction>(CmdSetStencilReference)},
11563593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdBindDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(CmdBindDescriptorSets)},
11564593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdBindVertexBuffers", reinterpret_cast<PFN_vkVoidFunction>(CmdBindVertexBuffers)},
11565593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdBindIndexBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdBindIndexBuffer)},
11566593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdDraw", reinterpret_cast<PFN_vkVoidFunction>(CmdDraw)},
11567593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdDrawIndexed", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndexed)},
11568593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdDrawIndirect", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndirect)},
11569593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdDrawIndexedIndirect", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndexedIndirect)},
11570593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdDispatch", reinterpret_cast<PFN_vkVoidFunction>(CmdDispatch)},
11571593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdDispatchIndirect", reinterpret_cast<PFN_vkVoidFunction>(CmdDispatchIndirect)},
11572593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdCopyBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyBuffer)},
11573593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdCopyImage", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyImage)},
11574593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdBlitImage", reinterpret_cast<PFN_vkVoidFunction>(CmdBlitImage)},
11575593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdCopyBufferToImage", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyBufferToImage)},
11576593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdCopyImageToBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyImageToBuffer)},
11577593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdUpdateBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdUpdateBuffer)},
11578593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdFillBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdFillBuffer)},
11579593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdClearColorImage", reinterpret_cast<PFN_vkVoidFunction>(CmdClearColorImage)},
11580593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdClearDepthStencilImage", reinterpret_cast<PFN_vkVoidFunction>(CmdClearDepthStencilImage)},
11581593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdClearAttachments", reinterpret_cast<PFN_vkVoidFunction>(CmdClearAttachments)},
11582593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdResolveImage", reinterpret_cast<PFN_vkVoidFunction>(CmdResolveImage)},
11583b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski        {"vkGetImageSubresourceLayout", reinterpret_cast<PFN_vkVoidFunction>(GetImageSubresourceLayout) },
11584593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetEvent", reinterpret_cast<PFN_vkVoidFunction>(CmdSetEvent)},
11585593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdResetEvent", reinterpret_cast<PFN_vkVoidFunction>(CmdResetEvent)},
11586593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdWaitEvents", reinterpret_cast<PFN_vkVoidFunction>(CmdWaitEvents)},
11587593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdPipelineBarrier", reinterpret_cast<PFN_vkVoidFunction>(CmdPipelineBarrier)},
11588593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdBeginQuery", reinterpret_cast<PFN_vkVoidFunction>(CmdBeginQuery)},
11589593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdEndQuery", reinterpret_cast<PFN_vkVoidFunction>(CmdEndQuery)},
11590593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdResetQueryPool", reinterpret_cast<PFN_vkVoidFunction>(CmdResetQueryPool)},
11591593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdCopyQueryPoolResults", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyQueryPoolResults)},
11592593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdPushConstants", reinterpret_cast<PFN_vkVoidFunction>(CmdPushConstants)},
11593593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdWriteTimestamp", reinterpret_cast<PFN_vkVoidFunction>(CmdWriteTimestamp)},
11594593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateFramebuffer", reinterpret_cast<PFN_vkVoidFunction>(CreateFramebuffer)},
11595593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateShaderModule", reinterpret_cast<PFN_vkVoidFunction>(CreateShaderModule)},
11596593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CreateRenderPass)},
11597593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdBeginRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CmdBeginRenderPass)},
11598593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdNextSubpass", reinterpret_cast<PFN_vkVoidFunction>(CmdNextSubpass)},
11599593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdEndRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CmdEndRenderPass)},
11600593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdExecuteCommands", reinterpret_cast<PFN_vkVoidFunction>(CmdExecuteCommands)},
11601593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkSetEvent", reinterpret_cast<PFN_vkVoidFunction>(SetEvent)},
11602593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkMapMemory", reinterpret_cast<PFN_vkVoidFunction>(MapMemory)},
11603593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkUnmapMemory", reinterpret_cast<PFN_vkVoidFunction>(UnmapMemory)},
11604593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkFlushMappedMemoryRanges", reinterpret_cast<PFN_vkVoidFunction>(FlushMappedMemoryRanges)},
11605593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkInvalidateMappedMemoryRanges", reinterpret_cast<PFN_vkVoidFunction>(InvalidateMappedMemoryRanges)},
11606593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkAllocateMemory", reinterpret_cast<PFN_vkVoidFunction>(AllocateMemory)},
11607593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkFreeMemory", reinterpret_cast<PFN_vkVoidFunction>(FreeMemory)},
11608593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkBindBufferMemory", reinterpret_cast<PFN_vkVoidFunction>(BindBufferMemory)},
11609593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkGetBufferMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(GetBufferMemoryRequirements)},
11610593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkGetImageMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(GetImageMemoryRequirements)},
11611593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkGetQueryPoolResults", reinterpret_cast<PFN_vkVoidFunction>(GetQueryPoolResults)},
11612593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkBindImageMemory", reinterpret_cast<PFN_vkVoidFunction>(BindImageMemory)},
11613593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkQueueBindSparse", reinterpret_cast<PFN_vkVoidFunction>(QueueBindSparse)},
11614593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateSemaphore", reinterpret_cast<PFN_vkVoidFunction>(CreateSemaphore)},
11615593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateEvent", reinterpret_cast<PFN_vkVoidFunction>(CreateEvent)},
1161680be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    };
1161780be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu
1161880be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    for (size_t i = 0; i < ARRAY_SIZE(core_device_commands); i++) {
11619cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!strcmp(core_device_commands[i].name, name)) return core_device_commands[i].proc;
1162080be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    }
1162180be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu
1162280be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    return nullptr;
1162380be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu}
1162480be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu
11625bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_khr_swapchain_command(const char *name, VkDevice dev) {
1162609a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu    static const struct {
1162709a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu        const char *name;
1162809a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu        PFN_vkVoidFunction proc;
1162909a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu    } khr_swapchain_commands[] = {
11630bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkCreateSwapchainKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateSwapchainKHR)},
11631bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkDestroySwapchainKHR", reinterpret_cast<PFN_vkVoidFunction>(DestroySwapchainKHR)},
11632bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkGetSwapchainImagesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetSwapchainImagesKHR)},
11633bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkAcquireNextImageKHR", reinterpret_cast<PFN_vkVoidFunction>(AcquireNextImageKHR)},
11634bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkQueuePresentKHR", reinterpret_cast<PFN_vkVoidFunction>(QueuePresentKHR)},
1163509a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu    };
11636c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young    layer_data *dev_data = nullptr;
1163709a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu
116383f6f8132355ebdae2736b31fc20de2ac60a70310Chia-I Wu    if (dev) {
1163956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        dev_data = GetLayerDataPtr(get_dispatch_key(dev), layer_data_map);
11640cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!dev_data->device_extensions.wsi_enabled) return nullptr;
116413f6f8132355ebdae2736b31fc20de2ac60a70310Chia-I Wu    }
1164209a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu
1164309a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu    for (size_t i = 0; i < ARRAY_SIZE(khr_swapchain_commands); i++) {
11644cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!strcmp(khr_swapchain_commands[i].name, name)) return khr_swapchain_commands[i].proc;
1164509a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu    }
1164609a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu
11647c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young    if (dev_data) {
11648cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!dev_data->device_extensions.wsi_display_swapchain_enabled) return nullptr;
11649c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young    }
11650c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young
11651cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!strcmp("vkCreateSharedSwapchainsKHR", name)) return reinterpret_cast<PFN_vkVoidFunction>(CreateSharedSwapchainsKHR);
11652c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young
1165309a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu    return nullptr;
11654747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11655747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11656bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_khr_surface_command(const char *name, VkInstance instance) {
11657747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    static const struct {
11658747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        const char *name;
11659747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        PFN_vkVoidFunction proc;
11660747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        bool instance_layer_data::*enable;
11661747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    } khr_surface_commands[] = {
11662747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_ANDROID_KHR
11663747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        {"vkCreateAndroidSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateAndroidSurfaceKHR),
11664bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::androidSurfaceExtensionEnabled},
11665cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_ANDROID_KHR
11666747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_MIR_KHR
11667747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        {"vkCreateMirSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateMirSurfaceKHR),
11668bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::mirSurfaceExtensionEnabled},
11669cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_MIR_KHR
11670747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WAYLAND_KHR
11671747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        {"vkCreateWaylandSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateWaylandSurfaceKHR),
11672bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::waylandSurfaceExtensionEnabled},
11673cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_WAYLAND_KHR
11674747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WIN32_KHR
11675747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        {"vkCreateWin32SurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateWin32SurfaceKHR),
11676bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::win32SurfaceExtensionEnabled},
11677cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_WIN32_KHR
11678747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XCB_KHR
11679747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        {"vkCreateXcbSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateXcbSurfaceKHR),
11680bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::xcbSurfaceExtensionEnabled},
11681cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_XCB_KHR
11682747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XLIB_KHR
11683747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        {"vkCreateXlibSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateXlibSurfaceKHR),
11684bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::xlibSurfaceExtensionEnabled},
11685cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_XLIB_KHR
11686bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkCreateDisplayPlaneSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateDisplayPlaneSurfaceKHR),
11687bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::displayExtensionEnabled},
11688747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        {"vkDestroySurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(DestroySurfaceKHR),
11689bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::surfaceExtensionEnabled},
1169040921785005eb449ec7c18229f0d84c879708b8aChris Forbes        {"vkGetPhysicalDeviceSurfaceCapabilitiesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfaceCapabilitiesKHR),
11691bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::surfaceExtensionEnabled},
11692418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes        {"vkGetPhysicalDeviceSurfaceSupportKHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfaceSupportKHR),
11693bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::surfaceExtensionEnabled},
116949e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        {"vkGetPhysicalDeviceSurfacePresentModesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfacePresentModesKHR),
11695bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::surfaceExtensionEnabled},
116965faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        {"vkGetPhysicalDeviceSurfaceFormatsKHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfaceFormatsKHR),
11697bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::surfaceExtensionEnabled},
11698747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    };
11699747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11700747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    instance_layer_data *instance_data = nullptr;
11701747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    if (instance) {
1170256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
11703747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
11704747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11705747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    for (size_t i = 0; i < ARRAY_SIZE(khr_surface_commands); i++) {
11706747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(khr_surface_commands[i].name, name)) {
11707cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (instance_data && !(instance_data->*(khr_surface_commands[i].enable))) return nullptr;
11708747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            return khr_surface_commands[i].proc;
11709747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        }
11710747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
11711747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11712747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return nullptr;
1171309a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu}
1171409a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu
1171543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic PFN_vkVoidFunction intercept_extension_instance_commands(const char *name, VkInstance instance) {
1171643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    static const struct {
1171743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        const char *name;
1171843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        PFN_vkVoidFunction proc;
1171943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        bool instance_layer_data::*enable;
1172043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    } instance_extension_commands[] = {
1172143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        {"vkGetPhysicalDeviceQueueFamilyProperties2KHR",
1172243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis         reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceQueueFamilyProperties2KHR)},
1172343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    };
1172443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1172543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    for (size_t i = 0; i < ARRAY_SIZE(instance_extension_commands); i++) {
1172643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        if (!strcmp(instance_extension_commands[i].name, name)) {
1172743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            return instance_extension_commands[i].proc;
1172843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        }
1172943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    }
1173043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    return nullptr;
1173143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
11732b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11733cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski}  // namespace core_validation
11734d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11735d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu// vk_layer_logging.h expects these to be defined
11736d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11737bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugReportCallbackEXT(VkInstance instance,
11738bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                              const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
11739bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                              const VkAllocationCallbacks *pAllocator,
11740bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                              VkDebugReportCallbackEXT *pMsgCallback) {
1174189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu    return core_validation::CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
11742d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
11743d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11744bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT msgCallback,
11745bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                           const VkAllocationCallbacks *pAllocator) {
1174689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu    core_validation::DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);
11747d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
11748d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11749bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL vkDebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags,
11750bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   VkDebugReportObjectTypeEXT objType, uint64_t object, size_t location,
11751bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
1175289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu    core_validation::DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, pMsg);
11753d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
11754d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11755a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu// loader-layer interface v0, just wrappers since there is only a layer
11756d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11757bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
11758bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                      VkExtensionProperties *pProperties) {
11759a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return core_validation::EnumerateInstanceExtensionProperties(pLayerName, pCount, pProperties);
1176008939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu}
1176108939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu
11762bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties(uint32_t *pCount,
11763bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                  VkLayerProperties *pProperties) {
11764a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return core_validation::EnumerateInstanceLayerProperties(pCount, pProperties);
1176508939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu}
1176608939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu
11767bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
11768bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                VkLayerProperties *pProperties) {
11769a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    // the layer command handles VK_NULL_HANDLE just fine internally
11770a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    assert(physicalDevice == VK_NULL_HANDLE);
11771a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return core_validation::EnumerateDeviceLayerProperties(VK_NULL_HANDLE, pCount, pProperties);
11772d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
11773d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11774d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I WuVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
11775d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu                                                                                    const char *pLayerName, uint32_t *pCount,
11776d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu                                                                                    VkExtensionProperties *pProperties) {
11777a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    // the layer command handles VK_NULL_HANDLE just fine internally
11778a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    assert(physicalDevice == VK_NULL_HANDLE);
11779a8f4a23b1e9c068717eda47cc583a93f447c77e3Chia-I Wu    return core_validation::EnumerateDeviceExtensionProperties(VK_NULL_HANDLE, pLayerName, pCount, pProperties);
11780d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
11781d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11782d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I WuVK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev, const char *funcName) {
1178389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu    return core_validation::GetDeviceProcAddr(dev, funcName);
11784d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
11785d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11786d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I WuVK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) {
1178789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu    return core_validation::GetInstanceProcAddr(instance, funcName);
1178808939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu}
11789b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11790bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_layerGetPhysicalDeviceProcAddr(VkInstance instance,
11791bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                           const char *funcName) {
11792b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    return core_validation::GetPhysicalDeviceProcAddr(instance, funcName);
11793b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young}
11794b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11795b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark YoungVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct) {
11796b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    assert(pVersionStruct != NULL);
11797b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    assert(pVersionStruct->sType == LAYER_NEGOTIATE_INTERFACE_STRUCT);
11798b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11799b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    // Fill in the function pointers if our version is at least capable of having the structure contain them.
11800b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    if (pVersionStruct->loaderLayerInterfaceVersion >= 2) {
11801b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        pVersionStruct->pfnGetInstanceProcAddr = vkGetInstanceProcAddr;
11802b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        pVersionStruct->pfnGetDeviceProcAddr = vkGetDeviceProcAddr;
11803b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        pVersionStruct->pfnGetPhysicalDeviceProcAddr = vk_layerGetPhysicalDeviceProcAddr;
11804b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    }
11805b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11806b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    if (pVersionStruct->loaderLayerInterfaceVersion < CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
11807b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        core_validation::loader_layer_if_version = pVersionStruct->loaderLayerInterfaceVersion;
11808b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    } else if (pVersionStruct->loaderLayerInterfaceVersion > CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
11809b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        pVersionStruct->loaderLayerInterfaceVersion = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
11810b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    }
11811b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11812b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    return VK_SUCCESS;
11813b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young}
11814