core_validation.cpp revision e659c986db0f3146726d6c744c75772316c3e0c6
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
7283a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// SetMemBinding is used to establish immutable, non-sparse binding between a single image/buffer object and memory object.
7293a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// Corresponding valid usage checks are in ValidateSetMemBinding().
730c18f059542c30f6b37f8a654df020be38adfade6Cort Strattonstatic void SetMemBinding(layer_data *dev_data, VkDeviceMemory mem, uint64_t handle, VkDebugReportObjectTypeEXT type,
731888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                          const char *apiName) {
732c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton    if (mem != VK_NULL_HANDLE) {
733c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        BINDABLE *mem_binding = GetObjectMemBinding(dev_data, handle, type);
734c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        assert(mem_binding);
735c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
736c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        if (mem_info) {
737c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton            mem_info->obj_bindings.insert({handle, type});
738c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton            // For image objects, make sure default memory state is correctly set
739c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton            // TODO : What's the best/correct way to handle this?
740c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton            if (VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT == type) {
741c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                auto const image_state = GetImageState(dev_data, VkImage(handle));
742c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                if (image_state) {
743c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                    VkImageCreateInfo ici = image_state->createInfo;
744c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                    if (ici.usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
745c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                        // TODO::  More memory state transition stuff.
746c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                    }
747c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                }
748c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton            }
749c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton            mem_binding->binding.mem = mem;
750c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        }
751c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton    }
752c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton}
7533a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton
7543a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// Valid usage checks for a call to SetMemBinding().
7553a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// For NULL mem case, output warning
7563a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// Make sure given object is in global object map
7573a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton//  IF a previous binding existed, output validation error
7583a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton//  Otherwise, add reference from objectInfo to memoryInfo
7593a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton//  Add reference off of objInfo
7603a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// TODO: We may need to refactor or pass in multiple valid usage statements to handle multiple valid usage conditions.
761c18f059542c30f6b37f8a654df020be38adfade6Cort Strattonstatic bool ValidateSetMemBinding(layer_data *dev_data, VkDeviceMemory mem, uint64_t handle, VkDebugReportObjectTypeEXT type,
762c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                                  const char *apiName) {
76383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
764f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    // It's an error to bind an object to NULL memory
765d3876b4ff7c293a14f73fe3622513d1fa91bf2d0Jeremy Hayes    if (mem != VK_NULL_HANDLE) {
766f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        BINDABLE *mem_binding = GetObjectMemBinding(dev_data, handle, type);
767888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis        assert(mem_binding);
76810ffe2d353eaff714ed92a2835af77d8b5042d31Cort        if (mem_binding->sparse) {
76910ffe2d353eaff714ed92a2835af77d8b5042d31Cort            UNIQUE_VALIDATION_ERROR_CODE error_code = VALIDATION_ERROR_00804;
77010ffe2d353eaff714ed92a2835af77d8b5042d31Cort            const char *handle_type = "IMAGE";
77174300755ed9ec780d6073af71e47f201217008d6Cort Stratton            if (strcmp(apiName, "vkBindBufferMemory()") == 0) {
77210ffe2d353eaff714ed92a2835af77d8b5042d31Cort                error_code = VALIDATION_ERROR_00792;
77310ffe2d353eaff714ed92a2835af77d8b5042d31Cort                handle_type = "BUFFER";
77410ffe2d353eaff714ed92a2835af77d8b5042d31Cort            } else {
77574300755ed9ec780d6073af71e47f201217008d6Cort Stratton                assert(strcmp(apiName, "vkBindImageMemory()") == 0);
77610ffe2d353eaff714ed92a2835af77d8b5042d31Cort            }
77710ffe2d353eaff714ed92a2835af77d8b5042d31Cort            skip_call |=
77810ffe2d353eaff714ed92a2835af77d8b5042d31Cort                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
77910ffe2d353eaff714ed92a2835af77d8b5042d31Cort                        reinterpret_cast<uint64_t &>(mem), __LINE__, error_code, "MEM",
78010ffe2d353eaff714ed92a2835af77d8b5042d31Cort                        "In %s, attempting to bind memory (0x%" PRIxLEAST64 ") to object (0x%" PRIxLEAST64
78110ffe2d353eaff714ed92a2835af77d8b5042d31Cort                        ") which was created with sparse memory flags (VK_%s_CREATE_SPARSE_*_BIT). %s",
78210ffe2d353eaff714ed92a2835af77d8b5042d31Cort                        apiName, reinterpret_cast<uint64_t &>(mem), handle, handle_type, validation_error_map[error_code]);
78310ffe2d353eaff714ed92a2835af77d8b5042d31Cort        }
7849a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
785888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis        if (mem_info) {
7869a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            DEVICE_MEM_INFO *prev_binding = GetMemObjInfo(dev_data, mem_binding->binding.mem);
787888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis            if (prev_binding) {
78898c2a17e1a549df84f4239f619bc0955f632cb43Cort                UNIQUE_VALIDATION_ERROR_CODE error_code = VALIDATION_ERROR_00803;
78974300755ed9ec780d6073af71e47f201217008d6Cort Stratton                if (strcmp(apiName, "vkBindBufferMemory()") == 0) {
79098c2a17e1a549df84f4239f619bc0955f632cb43Cort                    error_code = VALIDATION_ERROR_00791;
79198c2a17e1a549df84f4239f619bc0955f632cb43Cort                } else {
79274300755ed9ec780d6073af71e47f201217008d6Cort Stratton                    assert(strcmp(apiName, "vkBindImageMemory()") == 0);
79398c2a17e1a549df84f4239f619bc0955f632cb43Cort                }
794888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                skip_call |=
795888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
79698c2a17e1a549df84f4239f619bc0955f632cb43Cort                            reinterpret_cast<uint64_t &>(mem), __LINE__, error_code, "MEM",
797888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                            "In %s, attempting to bind memory (0x%" PRIxLEAST64 ") to object (0x%" PRIxLEAST64
79898c2a17e1a549df84f4239f619bc0955f632cb43Cort                            ") which has already been bound to mem object 0x%" PRIxLEAST64 ". %s",
79998c2a17e1a549df84f4239f619bc0955f632cb43Cort                            apiName, reinterpret_cast<uint64_t &>(mem), handle, reinterpret_cast<uint64_t &>(prev_binding->mem),
80098c2a17e1a549df84f4239f619bc0955f632cb43Cort                            validation_error_map[error_code]);
801f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis            } else if (mem_binding->binding.mem == MEMORY_UNBOUND) {
802888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                skip_call |=
803888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
804888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                            reinterpret_cast<uint64_t &>(mem), __LINE__, MEMTRACK_REBIND_OBJECT, "MEM",
805888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                            "In %s, attempting to bind memory (0x%" PRIxLEAST64 ") to object (0x%" PRIxLEAST64
806888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                            ") which was previous bound to memory that has since been freed. Memory bindings are immutable in "
807888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                            "Vulkan so this attempt to bind to new memory is not allowed.",
808888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                            apiName, reinterpret_cast<uint64_t &>(mem), handle);
8095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
8105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
81283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
8135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
8145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// For NULL mem case, clear any previous binding Else...
8165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Make sure given object is in its object map
8175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  IF a previous binding existed, update binding
8185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Add reference from objectInfo to memoryInfo
8195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Add reference off of object's binding info
8200a1ce3dfd81c9f4efbe46f5ba5ddaea70bc4aa61Chris Forbes// Return VK_TRUE if addition is successful, VK_FALSE otherwise
821f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlisstatic bool SetSparseMemBinding(layer_data *dev_data, MEM_BINDING binding, uint64_t handle, VkDebugReportObjectTypeEXT type,
822f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                                const char *apiName) {
82383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = VK_FALSE;
8245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Handle NULL case separately, just clear previous binding & decrement reference
825f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    if (binding.mem == VK_NULL_HANDLE) {
826f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        // TODO : This should cause the range of the resource to be unbound according to spec
8275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
828f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        BINDABLE *mem_binding = GetObjectMemBinding(dev_data, handle, type);
829f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        assert(mem_binding);
830f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        assert(mem_binding->sparse);
8319a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, binding.mem);
832f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        if (mem_info) {
833f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis            mem_info->obj_bindings.insert({handle, type});
8342e415b757c1e43fda35311aad026af8d5c96681cTobin Ehlis            // Need to set mem binding for this object
835f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis            mem_binding->sparse_bindings.insert(binding);
8365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
83883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
839caf05e0db4959ae196ab34b024f352d9c0326870Tobin Ehlis}
840caf05e0db4959ae196ab34b024f352d9c0326870Tobin Ehlis
8415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Return a string representation of CMD_TYPE enum
8425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic string cmdTypeToString(CMD_TYPE cmd) {
8435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (cmd) {
844cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_BINDPIPELINE:
845cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_BINDPIPELINE";
846cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_BINDPIPELINEDELTA:
847cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_BINDPIPELINEDELTA";
848cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETVIEWPORTSTATE:
849cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETVIEWPORTSTATE";
850cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETLINEWIDTHSTATE:
851cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETLINEWIDTHSTATE";
852cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETDEPTHBIASSTATE:
853cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETDEPTHBIASSTATE";
854cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETBLENDSTATE:
855cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETBLENDSTATE";
856cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETDEPTHBOUNDSSTATE:
857cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETDEPTHBOUNDSSTATE";
858cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETSTENCILREADMASKSTATE:
859cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETSTENCILREADMASKSTATE";
860cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETSTENCILWRITEMASKSTATE:
861cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETSTENCILWRITEMASKSTATE";
862cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETSTENCILREFERENCESTATE:
863cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETSTENCILREFERENCESTATE";
864cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_BINDDESCRIPTORSETS:
865cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_BINDDESCRIPTORSETS";
866cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_BINDINDEXBUFFER:
867cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_BINDINDEXBUFFER";
868cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_BINDVERTEXBUFFER:
869cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_BINDVERTEXBUFFER";
870cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_DRAW:
871cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_DRAW";
872cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_DRAWINDEXED:
873cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_DRAWINDEXED";
874cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_DRAWINDIRECT:
875cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_DRAWINDIRECT";
876cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_DRAWINDEXEDINDIRECT:
877cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_DRAWINDEXEDINDIRECT";
878cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_DISPATCH:
879cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_DISPATCH";
880cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_DISPATCHINDIRECT:
881cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_DISPATCHINDIRECT";
882cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_COPYBUFFER:
883cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_COPYBUFFER";
884cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_COPYIMAGE:
885cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_COPYIMAGE";
886cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_BLITIMAGE:
887cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_BLITIMAGE";
888cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_COPYBUFFERTOIMAGE:
889cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_COPYBUFFERTOIMAGE";
890cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_COPYIMAGETOBUFFER:
891cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_COPYIMAGETOBUFFER";
892cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_CLONEIMAGEDATA:
893cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_CLONEIMAGEDATA";
894cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_UPDATEBUFFER:
895cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_UPDATEBUFFER";
896cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_FILLBUFFER:
897cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_FILLBUFFER";
898cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_CLEARCOLORIMAGE:
899cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_CLEARCOLORIMAGE";
900cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_CLEARATTACHMENTS:
901cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_CLEARCOLORATTACHMENT";
902cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_CLEARDEPTHSTENCILIMAGE:
903cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_CLEARDEPTHSTENCILIMAGE";
904cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_RESOLVEIMAGE:
905cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_RESOLVEIMAGE";
906cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETEVENT:
907cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETEVENT";
908cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_RESETEVENT:
909cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_RESETEVENT";
910cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_WAITEVENTS:
911cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_WAITEVENTS";
912cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_PIPELINEBARRIER:
913cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_PIPELINEBARRIER";
914cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_BEGINQUERY:
915cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_BEGINQUERY";
916cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_ENDQUERY:
917cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_ENDQUERY";
918cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_RESETQUERYPOOL:
919cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_RESETQUERYPOOL";
920cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_COPYQUERYPOOLRESULTS:
921cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_COPYQUERYPOOLRESULTS";
922cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_WRITETIMESTAMP:
923cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_WRITETIMESTAMP";
924cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_INITATOMICCOUNTERS:
925cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_INITATOMICCOUNTERS";
926cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_LOADATOMICCOUNTERS:
927cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_LOADATOMICCOUNTERS";
928cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SAVEATOMICCOUNTERS:
929cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SAVEATOMICCOUNTERS";
930cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_BEGINRENDERPASS:
931cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_BEGINRENDERPASS";
932cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_ENDRENDERPASS:
933cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_ENDRENDERPASS";
934cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
935cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "UNKNOWN";
9365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
9385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// SPIRV utility functions
9405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic void build_def_index(shader_module *module) {
9415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *module) {
9425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        switch (insn.opcode()) {
943cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Types
944cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeVoid:
945cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeBool:
946cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeInt:
947cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeFloat:
948cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeVector:
949cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeMatrix:
950cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeImage:
951cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeSampler:
952cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeSampledImage:
953cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeArray:
954cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeRuntimeArray:
955cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeStruct:
956cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeOpaque:
957cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypePointer:
958cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeFunction:
959cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeEvent:
960cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeDeviceEvent:
961cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeReserveId:
962cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeQueue:
963cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypePipe:
964cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                module->def_index[insn.word(1)] = insn.offset();
965cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
9665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
967cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Fixed constants
968cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstantTrue:
969cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstantFalse:
970cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstant:
971cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstantComposite:
972cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstantSampler:
973cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstantNull:
974cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                module->def_index[insn.word(2)] = insn.offset();
975cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
9765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
977cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Specialization constants
978cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpSpecConstantTrue:
979cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpSpecConstantFalse:
980cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpSpecConstant:
981cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpSpecConstantComposite:
982cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpSpecConstantOp:
983cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                module->def_index[insn.word(2)] = insn.offset();
984cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
9855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
986cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Variables
987cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpVariable:
988cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                module->def_index[insn.word(2)] = insn.offset();
989cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
9905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
991cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Functions
992cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpFunction:
993cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                module->def_index[insn.word(2)] = insn.offset();
994cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
9955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
996cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
997cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // We don't care about any other defs for now.
998cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
9995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
10005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
10025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic spirv_inst_iter find_entrypoint(shader_module *src, char const *name, VkShaderStageFlagBits stageBits) {
10045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
10055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpEntryPoint) {
10065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            auto entrypointName = (char const *)&insn.word(3);
10075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            auto entrypointStageBits = 1u << insn.word(1);
10085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!strcmp(entrypointName, name) && (entrypointStageBits & stageBits)) {
10105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return insn;
10115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
10125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
10135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return src->end();
10165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
10175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic char const *storage_class_name(unsigned sc) {
10195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (sc) {
1020cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassInput:
1021cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "input";
1022cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassOutput:
1023cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "output";
1024cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassUniformConstant:
1025cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "const uniform";
1026cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassUniform:
1027cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "uniform";
1028cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassWorkgroup:
1029cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "workgroup local";
1030cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassCrossWorkgroup:
1031cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "workgroup global";
1032cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassPrivate:
1033cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "private global";
1034cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassFunction:
1035cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "function";
1036cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassGeneric:
1037cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "generic";
1038cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassAtomicCounter:
1039cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "atomic counter";
1040cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassImage:
1041cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "image";
1042cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassPushConstant:
1043cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "push constant";
1044cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1045cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "unknown";
10465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
10485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
104925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// Get the value of an integral constant
10505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisunsigned get_constant_value(shader_module const *src, unsigned id) {
10515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto value = src->get_def(id);
10525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(value != src->end());
10535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (value.opcode() != spv::OpConstant) {
105525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // TODO: Either ensure that the specialization transform is already performed on a module we're
105625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        //       considering here, OR -- specialize on the fly now.
10575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return 1;
10585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return value.word(3);
10615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
10625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10639ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbesstatic void describe_type_inner(std::ostringstream &ss, shader_module const *src, unsigned type) {
10645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto insn = src->get_def(type);
10655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(insn != src->end());
10665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (insn.opcode()) {
1068cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeBool:
1069cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "bool";
1070cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1071cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeInt:
1072cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << (insn.word(3) ? 's' : 'u') << "int" << insn.word(2);
1073cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1074cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeFloat:
1075cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "float" << insn.word(2);
1076cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1077cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeVector:
1078cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "vec" << insn.word(3) << " of ";
1079cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            describe_type_inner(ss, src, insn.word(2));
1080cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1081cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeMatrix:
1082cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "mat" << insn.word(3) << " of ";
1083cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            describe_type_inner(ss, src, insn.word(2));
1084cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1085cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeArray:
1086cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "arr[" << get_constant_value(src, insn.word(3)) << "] of ";
1087cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            describe_type_inner(ss, src, insn.word(2));
1088cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1089cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypePointer:
1090cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "ptr to " << storage_class_name(insn.word(2)) << " ";
1091cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            describe_type_inner(ss, src, insn.word(3));
1092cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1093cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeStruct: {
1094cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "struct of (";
1095cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            for (unsigned i = 2; i < insn.len(); i++) {
1096cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                describe_type_inner(ss, src, insn.word(i));
1097cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (i == insn.len() - 1) {
1098cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    ss << ")";
1099cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                } else {
1100cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    ss << ", ";
1101cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
11029ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes            }
1103cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
11045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
1105cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeSampler:
1106cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "sampler";
1107cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1108cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeSampledImage:
1109cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "sampler+";
1110cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            describe_type_inner(ss, src, insn.word(2));
1111cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1112cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeImage:
1113cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "image(dim=" << insn.word(3) << ", sampled=" << insn.word(7) << ")";
1114cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1115cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1116cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "oddtype";
1117cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
11185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
11195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
11205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11219ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbesstatic std::string describe_type(shader_module const *src, unsigned type) {
11229ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes    std::ostringstream ss;
11239ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes    describe_type_inner(ss, src, type);
11249ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes    return ss.str();
11259ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes}
11269ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes
1127bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool is_narrow_numeric_type(spirv_inst_iter type) {
1128cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (type.opcode() != spv::OpTypeInt && type.opcode() != spv::OpTypeFloat) return false;
112937576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes    return type.word(2) < 64;
113037576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes}
113137576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes
1132bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool types_match(shader_module const *a, shader_module const *b, unsigned a_type, unsigned b_type, bool a_arrayed,
1133bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        bool b_arrayed, bool relaxed) {
113425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Walk two type trees together, and complain about differences
11355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto a_insn = a->get_def(a_type);
11365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto b_insn = b->get_def(b_type);
11375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(a_insn != a->end());
11385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(b_insn != b->end());
11395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11407c755c8aca6857046df9516d8336416165969cb9Chris Forbes    if (a_arrayed && a_insn.opcode() == spv::OpTypeArray) {
114137576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes        return types_match(a, b, a_insn.word(2), b_type, false, b_arrayed, relaxed);
11427c755c8aca6857046df9516d8336416165969cb9Chris Forbes    }
11437c755c8aca6857046df9516d8336416165969cb9Chris Forbes
11445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (b_arrayed && b_insn.opcode() == spv::OpTypeArray) {
114525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // We probably just found the extra level of arrayness in b_type: compare the type inside it to a_type
114637576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes        return types_match(a, b, a_type, b_insn.word(2), a_arrayed, false, relaxed);
114737576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes    }
114837576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes
114937576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes    if (a_insn.opcode() == spv::OpTypeVector && relaxed && is_narrow_numeric_type(b_insn)) {
115037576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes        return types_match(a, b, a_insn.word(2), b_type, a_arrayed, b_arrayed, false);
11515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
11525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (a_insn.opcode() != b_insn.opcode()) {
11545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return false;
11555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
11565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11577c755c8aca6857046df9516d8336416165969cb9Chris Forbes    if (a_insn.opcode() == spv::OpTypePointer) {
115825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Match on pointee type. storage class is expected to differ
115937576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes        return types_match(a, b, a_insn.word(3), b_insn.word(3), a_arrayed, b_arrayed, relaxed);
11607c755c8aca6857046df9516d8336416165969cb9Chris Forbes    }
11617c755c8aca6857046df9516d8336416165969cb9Chris Forbes
11627c755c8aca6857046df9516d8336416165969cb9Chris Forbes    if (a_arrayed || b_arrayed) {
116325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // If we havent resolved array-of-verts by here, we're not going to.
11647c755c8aca6857046df9516d8336416165969cb9Chris Forbes        return false;
11657c755c8aca6857046df9516d8336416165969cb9Chris Forbes    }
11667c755c8aca6857046df9516d8336416165969cb9Chris Forbes
11675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (a_insn.opcode()) {
1168cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeBool:
1169cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return true;
1170cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeInt:
1171cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on width, signedness
1172cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return a_insn.word(2) == b_insn.word(2) && a_insn.word(3) == b_insn.word(3);
1173cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeFloat:
1174cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on width
1175cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return a_insn.word(2) == b_insn.word(2);
1176cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeVector:
1177cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on element type, count.
1178cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (!types_match(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false)) return false;
1179cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (relaxed && is_narrow_numeric_type(a->get_def(a_insn.word(2)))) {
1180cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return a_insn.word(3) >= b_insn.word(3);
1181cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else {
1182cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return a_insn.word(3) == b_insn.word(3);
11835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
1184cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeMatrix:
1185cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on element type, count.
1186cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return types_match(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false) &&
1187cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                   a_insn.word(3) == b_insn.word(3);
1188cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeArray:
1189cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on element type, count. these all have the same layout. we don't get here if b_arrayed. This differs from
1190cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // vector & matrix types in that the array size is the id of a constant instruction, * not a literal within OpTypeArray
1191cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return types_match(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false) &&
1192cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                   get_constant_value(a, a_insn.word(3)) == get_constant_value(b, b_insn.word(3));
1193cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeStruct:
1194cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on all element types
1195cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            {
1196cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (a_insn.len() != b_insn.len()) {
1197cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    return false;  // Structs cannot match if member counts differ
1198cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
11995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1200cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                for (unsigned i = 2; i < a_insn.len(); i++) {
1201cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    if (!types_match(a, b, a_insn.word(i), b_insn.word(i), a_arrayed, b_arrayed, false)) {
1202cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return false;
1203cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    }
1204cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
1205cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski
1206cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return true;
1207cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
1208cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1209cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Remaining types are CLisms, or may not appear in the interfaces we are interested in. Just claim no match.
1210cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return false;
12115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
12125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
12135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic int value_or_default(std::unordered_map<unsigned, unsigned> const &map, unsigned id, int def) {
12155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto it = map.find(id);
12165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (it == map.end())
12175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return def;
12185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    else
12195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return it->second;
12205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
12215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic unsigned get_locations_consumed_by_type(shader_module const *src, unsigned type, bool strip_array_level) {
12235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto insn = src->get_def(type);
12245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(insn != src->end());
12255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (insn.opcode()) {
1227cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypePointer:
1228cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // See through the ptr -- this is only ever at the toplevel for graphics shaders we're never actually passing
1229cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // pointers around.
1230cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_locations_consumed_by_type(src, insn.word(3), strip_array_level);
1231cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeArray:
1232cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (strip_array_level) {
1233cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return get_locations_consumed_by_type(src, insn.word(2), false);
1234cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else {
1235cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return get_constant_value(src, insn.word(3)) * get_locations_consumed_by_type(src, insn.word(2), false);
1236cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
1237cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeMatrix:
1238cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Num locations is the dimension * element size
1239cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return insn.word(3) * get_locations_consumed_by_type(src, insn.word(2), false);
1240cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeVector: {
1241cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            auto scalar_type = src->get_def(insn.word(2));
1242cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            auto bit_width =
1243cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                (scalar_type.opcode() == spv::OpTypeInt || scalar_type.opcode() == spv::OpTypeFloat) ? scalar_type.word(2) : 32;
1244cc52143fc093e1e62d2dacc4abc3966e04b6f6d6Chris Forbes
1245cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Locations are 128-bit wide; 3- and 4-component vectors of 64 bit types require two.
1246cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return (bit_width * insn.word(3) + 127) / 128;
1247cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
1248cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1249cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Everything else is just 1.
1250cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return 1;
12515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1252cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // TODO: extend to handle 64bit scalar types, whose vectors may need multiple locations.
12535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
12545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
12555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1256c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbesstatic unsigned get_locations_consumed_by_format(VkFormat format) {
1257c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes    switch (format) {
1258cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64A64_SFLOAT:
1259cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64A64_SINT:
1260cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64A64_UINT:
1261cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64_SFLOAT:
1262cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64_SINT:
1263cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64_UINT:
1264cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return 2;
1265cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1266cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return 1;
1267c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes    }
1268c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes}
1269c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes
12705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlistypedef std::pair<unsigned, unsigned> location_t;
12715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlistypedef std::pair<unsigned, unsigned> descriptor_slot_t;
12725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstruct interface_var {
12745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t id;
12755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t type_id;
12765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t offset;
1277b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes    bool is_patch;
1278fff9393206f66a154438e16fa0562c989f425498Chris Forbes    bool is_block_member;
1279b0436668e6594b8528e96de7bed208399fb2431dChris Forbes    bool is_relaxed_precision;
128025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // TODO: collect the name, too? Isn't required to be present.
12815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis};
12825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1283031261d21af8907953dd763398ce9a23e65b8749Chris Forbesstruct shader_stage_attributes {
1284031261d21af8907953dd763398ce9a23e65b8749Chris Forbes    char const *const name;
1285031261d21af8907953dd763398ce9a23e65b8749Chris Forbes    bool arrayed_input;
1286031261d21af8907953dd763398ce9a23e65b8749Chris Forbes    bool arrayed_output;
1287031261d21af8907953dd763398ce9a23e65b8749Chris Forbes};
1288031261d21af8907953dd763398ce9a23e65b8749Chris Forbes
1289031261d21af8907953dd763398ce9a23e65b8749Chris Forbesstatic shader_stage_attributes shader_stage_attribs[] = {
1290bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    {"vertex shader", false, false},  {"tessellation control shader", true, true}, {"tessellation evaluation shader", true, false},
1291bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    {"geometry shader", true, false}, {"fragment shader", false, false},
1292031261d21af8907953dd763398ce9a23e65b8749Chris Forbes};
1293031261d21af8907953dd763398ce9a23e65b8749Chris Forbes
12945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic spirv_inst_iter get_struct_type(shader_module const *src, spirv_inst_iter def, bool is_array_of_verts) {
12955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while (true) {
12965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (def.opcode() == spv::OpTypePointer) {
12975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            def = src->get_def(def.word(3));
12985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (def.opcode() == spv::OpTypeArray && is_array_of_verts) {
12995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            def = src->get_def(def.word(2));
13005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            is_array_of_verts = false;
13015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (def.opcode() == spv::OpTypeStruct) {
13025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return def;
13035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
13045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return src->end();
13055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
13065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
13075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
13085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1309bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic void collect_interface_block_members(shader_module const *src, std::map<location_t, interface_var> *out,
13105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                            std::unordered_map<unsigned, unsigned> const &blocks, bool is_array_of_verts,
1311b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes                                            uint32_t id, uint32_t type_id, bool is_patch) {
131225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Walk down the type_id presented, trying to determine whether it's actually an interface block.
1313031261d21af8907953dd763398ce9a23e65b8749Chris Forbes    auto type = get_struct_type(src, src->get_def(type_id), is_array_of_verts && !is_patch);
13145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (type == src->end() || blocks.find(type.word(1)) == blocks.end()) {
131525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // This isn't an interface block.
13165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return;
13175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
13185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> member_components;
13205b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes    std::unordered_map<unsigned, unsigned> member_relaxed_precision;
13215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
132225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Walk all the OpMemberDecorate for type's result id -- first pass, collect components.
13235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
13245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
13255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned member_index = insn.word(2);
13265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(3) == spv::DecorationComponent) {
13285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                unsigned component = insn.word(4);
13295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                member_components[member_index] = component;
13305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
13315b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes
13325b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes            if (insn.word(3) == spv::DecorationRelaxedPrecision) {
13335b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes                member_relaxed_precision[member_index] = 1;
13345b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes            }
13355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
13365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
13375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
133825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Second pass -- produce the output, from Location decorations
13395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
13405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
13415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned member_index = insn.word(2);
13425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned member_type_id = type.word(2 + member_index);
13435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(3) == spv::DecorationLocation) {
13455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                unsigned location = insn.word(4);
13465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                unsigned num_locations = get_locations_consumed_by_type(src, member_type_id, false);
13475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                auto component_it = member_components.find(member_index);
13485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                unsigned component = component_it == member_components.end() ? 0 : component_it->second;
13495b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes                bool is_relaxed_precision = member_relaxed_precision.find(member_index) != member_relaxed_precision.end();
13505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                for (unsigned int offset = 0; offset < num_locations; offset++) {
1352b0436668e6594b8528e96de7bed208399fb2431dChris Forbes                    interface_var v = {};
13535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.id = id;
135425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski                    // TODO: member index in interface_var too?
13555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.type_id = member_type_id;
13565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.offset = offset;
1357b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes                    v.is_patch = is_patch;
1358fff9393206f66a154438e16fa0562c989f425498Chris Forbes                    v.is_block_member = true;
13595b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes                    v.is_relaxed_precision = is_relaxed_precision;
13603a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes                    (*out)[std::make_pair(location + offset, component)] = v;
13615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
13625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
13635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
13645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
13655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
13665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1367bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic std::map<location_t, interface_var> collect_interface_by_location(shader_module const *src, spirv_inst_iter entrypoint,
1368bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                         spv::StorageClass sinterface, bool is_array_of_verts) {
13695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> var_locations;
13705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> var_builtins;
13715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> var_components;
13725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> blocks;
1373b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes    std::unordered_map<unsigned, unsigned> var_patch;
1374b0436668e6594b8528e96de7bed208399fb2431dChris Forbes    std::unordered_map<unsigned, unsigned> var_relaxed_precision;
13755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
137725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // We consider two interface models: SSO rendezvous-by-location, and builtins. Complain about anything that
137825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // fits neither model.
13795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpDecorate) {
13805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationLocation) {
13815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                var_locations[insn.word(1)] = insn.word(3);
13825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
13835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationBuiltIn) {
13855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                var_builtins[insn.word(1)] = insn.word(3);
13865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
13875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationComponent) {
13895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                var_components[insn.word(1)] = insn.word(3);
13905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
13915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationBlock) {
13935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                blocks[insn.word(1)] = 1;
13945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
1395b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes
1396b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes            if (insn.word(2) == spv::DecorationPatch) {
1397b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes                var_patch[insn.word(1)] = 1;
1398b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes            }
1399b0436668e6594b8528e96de7bed208399fb2431dChris Forbes
1400b0436668e6594b8528e96de7bed208399fb2431dChris Forbes            if (insn.word(2) == spv::DecorationRelaxedPrecision) {
1401b0436668e6594b8528e96de7bed208399fb2431dChris Forbes                var_relaxed_precision[insn.word(1)] = 1;
1402b0436668e6594b8528e96de7bed208399fb2431dChris Forbes            }
14035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
14045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
14055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
140625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // TODO: handle grouped decorations
140725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // TODO: handle index=1 dual source outputs from FS -- two vars will have the same location, and we DON'T want to clobber.
14085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
140925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Find the end of the entrypoint's name string. additional zero bytes follow the actual null terminator, to fill out the
141025002b75574f762c62b1a00a595bab04ebb25452Mark 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.
1411c15b801a6e1a5dd5eed09e689aecdde7c4a90a5bMichael Mc Donnell    uint32_t word = 3;
14125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while (entrypoint.word(word) & 0xff000000u) {
14135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        ++word;
14145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
14155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    ++word;
14165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14173a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    std::map<location_t, interface_var> out;
14183a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
14195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (; word < entrypoint.len(); word++) {
14205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto insn = src->get_def(entrypoint.word(word));
14215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        assert(insn != src->end());
14225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        assert(insn.opcode() == spv::OpVariable);
14235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14241d5109d5e0dcc530b27e632e73e1be5e12a28dcdJamie Madill        if (insn.word(3) == static_cast<uint32_t>(sinterface)) {
14255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned id = insn.word(2);
14265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned type = insn.word(1);
14275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            int location = value_or_default(var_locations, id, -1);
14295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            int builtin = value_or_default(var_builtins, id, -1);
1430cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            unsigned component = value_or_default(var_components, id, 0);  // Unspecified is OK, is 0
1431b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes            bool is_patch = var_patch.find(id) != var_patch.end();
1432b0436668e6594b8528e96de7bed208399fb2431dChris Forbes            bool is_relaxed_precision = var_relaxed_precision.find(id) != var_relaxed_precision.end();
14335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
143425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // All variables and interface block members in the Input or Output storage classes must be decorated with either
143525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // a builtin or an explicit location.
143625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            //
143725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // TODO: integrate the interface block support here. For now, don't complain -- a valid SPIRV module will only hit
143825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // this path for the interface block case, as the individual members of the type are decorated, rather than
143925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // variable declarations.
14405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (location != -1) {
144225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski                // A user-defined interface variable, with a location. Where a variable occupied multiple locations, emit
144325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski                // one result for each.
14447c755c8aca6857046df9516d8336416165969cb9Chris Forbes                unsigned num_locations = get_locations_consumed_by_type(src, type, is_array_of_verts && !is_patch);
14455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                for (unsigned int offset = 0; offset < num_locations; offset++) {
1446b0436668e6594b8528e96de7bed208399fb2431dChris Forbes                    interface_var v = {};
14475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.id = id;
14485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.type_id = type;
14495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.offset = offset;
1450b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes                    v.is_patch = is_patch;
1451b0436668e6594b8528e96de7bed208399fb2431dChris Forbes                    v.is_relaxed_precision = is_relaxed_precision;
14525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    out[std::make_pair(location + offset, component)] = v;
14535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
14545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else if (builtin == -1) {
145525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski                // An interface block instance
14563a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes                collect_interface_block_members(src, &out, blocks, is_array_of_verts, id, type, is_patch);
14575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
14585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
14595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
14603a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
14613a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    return out;
14625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
14635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1464cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskistatic std::vector<std::pair<uint32_t, interface_var>> collect_interface_by_input_attachment_index(
1465cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    debug_report_data *report_data, shader_module const *src, std::unordered_set<uint32_t> const &accessible_ids) {
14663a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    std::vector<std::pair<uint32_t, interface_var>> out;
1467745d49409296f060402b57950384caadb636a2b2Chris Forbes
1468745d49409296f060402b57950384caadb636a2b2Chris Forbes    for (auto insn : *src) {
1469745d49409296f060402b57950384caadb636a2b2Chris Forbes        if (insn.opcode() == spv::OpDecorate) {
1470745d49409296f060402b57950384caadb636a2b2Chris Forbes            if (insn.word(2) == spv::DecorationInputAttachmentIndex) {
1471745d49409296f060402b57950384caadb636a2b2Chris Forbes                auto attachment_index = insn.word(3);
1472745d49409296f060402b57950384caadb636a2b2Chris Forbes                auto id = insn.word(1);
1473745d49409296f060402b57950384caadb636a2b2Chris Forbes
1474745d49409296f060402b57950384caadb636a2b2Chris Forbes                if (accessible_ids.count(id)) {
1475745d49409296f060402b57950384caadb636a2b2Chris Forbes                    auto def = src->get_def(id);
1476745d49409296f060402b57950384caadb636a2b2Chris Forbes                    assert(def != src->end());
1477745d49409296f060402b57950384caadb636a2b2Chris Forbes
1478745d49409296f060402b57950384caadb636a2b2Chris Forbes                    if (def.opcode() == spv::OpVariable && insn.word(3) == spv::StorageClassUniformConstant) {
1479e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                        auto num_locations = get_locations_consumed_by_type(src, def.word(1), false);
1480e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                        for (unsigned int offset = 0; offset < num_locations; offset++) {
1481b0436668e6594b8528e96de7bed208399fb2431dChris Forbes                            interface_var v = {};
1482e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                            v.id = id;
1483e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                            v.type_id = def.word(1);
1484e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                            v.offset = offset;
1485e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                            out.emplace_back(attachment_index + offset, v);
1486e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                        }
1487745d49409296f060402b57950384caadb636a2b2Chris Forbes                    }
1488745d49409296f060402b57950384caadb636a2b2Chris Forbes                }
1489745d49409296f060402b57950384caadb636a2b2Chris Forbes            }
1490745d49409296f060402b57950384caadb636a2b2Chris Forbes        }
1491745d49409296f060402b57950384caadb636a2b2Chris Forbes    }
14923a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
14933a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    return out;
1494745d49409296f060402b57950384caadb636a2b2Chris Forbes}
1495745d49409296f060402b57950384caadb636a2b2Chris Forbes
1496cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskistatic std::vector<std::pair<descriptor_slot_t, interface_var>> collect_interface_by_descriptor_slot(
1497cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    debug_report_data *report_data, shader_module const *src, std::unordered_set<uint32_t> const &accessible_ids) {
14985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> var_sets;
14995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> var_bindings;
15005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
150225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // All variables in the Uniform or UniformConstant storage classes are required to be decorated with both
150325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // DecorationDescriptorSet and DecorationBinding.
15045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpDecorate) {
15055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationDescriptorSet) {
15065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                var_sets[insn.word(1)] = insn.word(3);
15075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
15085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationBinding) {
15105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                var_bindings[insn.word(1)] = insn.word(3);
15115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
15125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
15135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
15145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15153a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    std::vector<std::pair<descriptor_slot_t, interface_var>> out;
15163a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
15175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto id : accessible_ids) {
15185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto insn = src->get_def(id);
15195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        assert(insn != src->end());
15205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpVariable &&
15225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            (insn.word(3) == spv::StorageClassUniform || insn.word(3) == spv::StorageClassUniformConstant)) {
15235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned set = value_or_default(var_sets, insn.word(2), 0);
15245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned binding = value_or_default(var_bindings, insn.word(2), 0);
15255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1526b0436668e6594b8528e96de7bed208399fb2431dChris Forbes            interface_var v = {};
15275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            v.id = insn.word(2);
15285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            v.type_id = insn.word(1);
1529cefd4dd8e03c5dae11a05d04a03cb856190358e0Chris Forbes            out.emplace_back(std::make_pair(set, binding), v);
15305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
15315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
15323a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
15333a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    return out;
15345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
15355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1536edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_interface_between_stages(debug_report_data *report_data, shader_module const *producer,
1537031261d21af8907953dd763398ce9a23e65b8749Chris Forbes                                              spirv_inst_iter producer_entrypoint, shader_stage_attributes const *producer_stage,
15385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                              shader_module const *consumer, spirv_inst_iter consumer_entrypoint,
1539031261d21af8907953dd763398ce9a23e65b8749Chris Forbes                                              shader_stage_attributes const *consumer_stage) {
15405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool pass = true;
15415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1542bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto outputs =
1543bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        collect_interface_by_location(producer, producer_entrypoint, spv::StorageClassOutput, producer_stage->arrayed_output);
1544bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto inputs =
1545bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        collect_interface_by_location(consumer, consumer_entrypoint, spv::StorageClassInput, consumer_stage->arrayed_input);
15465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto a_it = outputs.begin();
15485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto b_it = inputs.begin();
15495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
155025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Maps sorted by key (location); walk them together to find mismatches
15515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while ((outputs.size() > 0 && a_it != outputs.end()) || (inputs.size() && b_it != inputs.end())) {
15525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        bool a_at_end = outputs.size() == 0 || a_it == outputs.end();
15535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        bool b_at_end = inputs.size() == 0 || b_it == inputs.end();
15545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto a_first = a_at_end ? std::make_pair(0u, 0u) : a_it->first;
15555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto b_first = b_at_end ? std::make_pair(0u, 0u) : b_it->first;
15565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (b_at_end || ((!a_at_end) && (a_first < b_first))) {
1558bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
1559bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC", "%s writes to output location %u.%u which is not consumed by %s",
1560bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        producer_stage->name, a_first.first, a_first.second, consumer_stage->name)) {
15615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pass = false;
15625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
15635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            a_it++;
15645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (a_at_end || a_first > b_first) {
1565bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
1566bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "%s consumes input location %u.%u which is not written by %s",
1567bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        consumer_stage->name, b_first.first, b_first.second, producer_stage->name)) {
15685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pass = false;
15695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
15705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            b_it++;
15715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
1572fff9393206f66a154438e16fa0562c989f425498Chris Forbes            // subtleties of arrayed interfaces:
1573fff9393206f66a154438e16fa0562c989f425498Chris Forbes            // - if is_patch, then the member is not arrayed, even though the interface may be.
1574fff9393206f66a154438e16fa0562c989f425498Chris Forbes            // - if is_block_member, then the extra array level of an arrayed interface is not
1575fff9393206f66a154438e16fa0562c989f425498Chris Forbes            //   expressed in the member type -- it's expressed in the block type.
15760f44c68c2575ba2fc83d8c8f2f5ea09548f40686Chris Forbes            if (!types_match(producer, consumer, a_it->second.type_id, b_it->second.type_id,
1577fff9393206f66a154438e16fa0562c989f425498Chris Forbes                             producer_stage->arrayed_output && !a_it->second.is_patch && !a_it->second.is_block_member,
1578bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             consumer_stage->arrayed_input && !b_it->second.is_patch && !b_it->second.is_block_member, true)) {
1579bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
1580bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC", "Type mismatch on location %u.%u: '%s' vs '%s'",
1581bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            a_first.first, a_first.second, describe_type(producer, a_it->second.type_id).c_str(),
15829ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes                            describe_type(consumer, b_it->second.type_id).c_str())) {
15835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    pass = false;
15845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
15855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
15860f44c68c2575ba2fc83d8c8f2f5ea09548f40686Chris Forbes            if (a_it->second.is_patch != b_it->second.is_patch) {
1587bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
1588bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
1589f706c50be3a9d4d1e131c2f43ee2fb443f028d30Chris Forbes                            "Decoration mismatch on location %u.%u: is per-%s in %s stage but "
1590bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "per-%s in %s stage",
1591bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            a_first.first, a_first.second, a_it->second.is_patch ? "patch" : "vertex", producer_stage->name,
15920f44c68c2575ba2fc83d8c8f2f5ea09548f40686Chris Forbes                            b_it->second.is_patch ? "patch" : "vertex", consumer_stage->name)) {
15930f44c68c2575ba2fc83d8c8f2f5ea09548f40686Chris Forbes                    pass = false;
15940f44c68c2575ba2fc83d8c8f2f5ea09548f40686Chris Forbes                }
15950f44c68c2575ba2fc83d8c8f2f5ea09548f40686Chris Forbes            }
159617c6bacf91ac671cb33212071b87b8ea782812f5Chris Forbes            if (a_it->second.is_relaxed_precision != b_it->second.is_relaxed_precision) {
1597bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
1598bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
1599bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "Decoration mismatch on location %u.%u: %s and %s stages differ in precision", a_first.first,
1600bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            a_first.second, producer_stage->name, consumer_stage->name)) {
160117c6bacf91ac671cb33212071b87b8ea782812f5Chris Forbes                    pass = false;
160217c6bacf91ac671cb33212071b87b8ea782812f5Chris Forbes                }
160317c6bacf91ac671cb33212071b87b8ea782812f5Chris Forbes            }
16045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            a_it++;
16055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            b_it++;
16065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
16075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
16085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
16095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return pass;
16105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
16115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
16125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisenum FORMAT_TYPE {
16135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    FORMAT_TYPE_UNDEFINED,
1614cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    FORMAT_TYPE_FLOAT,  // UNORM, SNORM, FLOAT, USCALED, SSCALED, SRGB -- anything we consider float in the shader
16155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    FORMAT_TYPE_SINT,
16165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    FORMAT_TYPE_UINT,
16175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis};
16185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
16195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic unsigned get_format_type(VkFormat fmt) {
16205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (fmt) {
1621cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_UNDEFINED:
1622cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return FORMAT_TYPE_UNDEFINED;
1623cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R8_SINT:
1624cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R8G8_SINT:
1625cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R8G8B8_SINT:
1626cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R8G8B8A8_SINT:
1627cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R16_SINT:
1628cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R16G16_SINT:
1629cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R16G16B16_SINT:
1630cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R16G16B16A16_SINT:
1631cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R32_SINT:
1632cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R32G32_SINT:
1633cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R32G32B32_SINT:
1634cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R32G32B32A32_SINT:
1635cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64_SINT:
1636cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64_SINT:
1637cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64_SINT:
1638cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64A64_SINT:
1639cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_B8G8R8_SINT:
1640cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_B8G8R8A8_SINT:
1641cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_A8B8G8R8_SINT_PACK32:
1642cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_A2B10G10R10_SINT_PACK32:
1643cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_A2R10G10B10_SINT_PACK32:
1644cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return FORMAT_TYPE_SINT;
1645cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R8_UINT:
1646cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R8G8_UINT:
1647cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R8G8B8_UINT:
1648cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R8G8B8A8_UINT:
1649cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R16_UINT:
1650cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R16G16_UINT:
1651cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R16G16B16_UINT:
1652cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R16G16B16A16_UINT:
1653cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R32_UINT:
1654cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R32G32_UINT:
1655cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R32G32B32_UINT:
1656cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R32G32B32A32_UINT:
1657cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64_UINT:
1658cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64_UINT:
1659cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64_UINT:
1660cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64A64_UINT:
1661cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_B8G8R8_UINT:
1662cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_B8G8R8A8_UINT:
1663cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_A8B8G8R8_UINT_PACK32:
1664cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_A2B10G10R10_UINT_PACK32:
1665cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_A2R10G10B10_UINT_PACK32:
1666cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return FORMAT_TYPE_UINT;
1667cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1668cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return FORMAT_TYPE_FLOAT;
16695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
16705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
16715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
167225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// characterizes a SPIR-V type appearing in an interface to a FF stage, for comparison to a VkFormat's characterization above.
16735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic unsigned get_fundamental_type(shader_module const *src, unsigned type) {
16745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto insn = src->get_def(type);
16755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(insn != src->end());
16765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
16775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (insn.opcode()) {
1678cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeInt:
1679cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return insn.word(3) ? FORMAT_TYPE_SINT : FORMAT_TYPE_UINT;
1680cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeFloat:
1681cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return FORMAT_TYPE_FLOAT;
1682cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeVector:
1683cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_fundamental_type(src, insn.word(2));
1684cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeMatrix:
1685cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_fundamental_type(src, insn.word(2));
1686cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeArray:
1687cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_fundamental_type(src, insn.word(2));
1688cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypePointer:
1689cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_fundamental_type(src, insn.word(3));
1690cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeImage:
1691cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_fundamental_type(src, insn.word(2));
1692cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski
1693cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1694cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return FORMAT_TYPE_UNDEFINED;
16955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
16965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
16975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
16985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic uint32_t get_shader_stage_id(VkShaderStageFlagBits stage) {
16995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t bit_pos = u_ffs(stage);
17005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return bit_pos - 1;
17015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
17025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1703edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_vi_consistency(debug_report_data *report_data, VkPipelineVertexInputStateCreateInfo const *vi) {
170425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Walk the binding descriptions, which describe the step rate and stride of each vertex buffer.  Each binding should
170525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // be specified only once.
17065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<uint32_t, VkVertexInputBindingDescription const *> bindings;
17075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool pass = true;
17085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (unsigned i = 0; i < vi->vertexBindingDescriptionCount; i++) {
17105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto desc = &vi->pVertexBindingDescriptions[i];
17115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto &binding = bindings[desc->binding];
17125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (binding) {
17134f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes            // TODO: VALIDATION_ERROR_02105 perhaps?
1714bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
1715bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        SHADER_CHECKER_INCONSISTENT_VI, "SC", "Duplicate vertex input binding descriptions for binding %d",
1716bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        desc->binding)) {
17175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pass = false;
17185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
17195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
17205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            binding = desc;
17215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
17225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
17235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return pass;
17255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
17265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1727edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_vi_against_vs_inputs(debug_report_data *report_data, VkPipelineVertexInputStateCreateInfo const *vi,
17285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                          shader_module const *vs, spirv_inst_iter entrypoint) {
17295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool pass = true;
17305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17313a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    auto inputs = collect_interface_by_location(vs, entrypoint, spv::StorageClassInput, false);
17325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
173325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Build index by location
17345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::map<uint32_t, VkVertexInputAttributeDescription const *> attribs;
17355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (vi) {
1736c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes        for (unsigned i = 0; i < vi->vertexAttributeDescriptionCount; i++) {
1737c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes            auto num_locations = get_locations_consumed_by_format(vi->pVertexAttributeDescriptions[i].format);
1738c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes            for (auto j = 0u; j < num_locations; j++) {
1739c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes                attribs[vi->pVertexAttributeDescriptions[i].location + j] = &vi->pVertexAttributeDescriptions[i];
1740c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes            }
1741c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes        }
17425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
17435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto it_a = attribs.begin();
17455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto it_b = inputs.begin();
17461730e0dd28b3abc660b4e4704cf6d414f7fd4ad6Chris Forbes    bool used = false;
17475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while ((attribs.size() > 0 && it_a != attribs.end()) || (inputs.size() > 0 && it_b != inputs.end())) {
17495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        bool a_at_end = attribs.size() == 0 || it_a == attribs.end();
17505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        bool b_at_end = inputs.size() == 0 || it_b == inputs.end();
17515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto a_first = a_at_end ? 0 : it_a->first;
17525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto b_first = b_at_end ? 0 : it_b->first.first;
17535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!a_at_end && (b_at_end || a_first < b_first)) {
17541730e0dd28b3abc660b4e4704cf6d414f7fd4ad6Chris Forbes            if (!used && log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
1755bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 __LINE__, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",
1756bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 "Vertex attribute at location %d not consumed by vertex shader", a_first)) {
17575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pass = false;
17585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
17591730e0dd28b3abc660b4e4704cf6d414f7fd4ad6Chris Forbes            used = false;
17605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            it_a++;
17615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (!b_at_end && (a_at_end || b_first < a_first)) {
1762bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
1763bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "Vertex shader consumes input at location %d but not provided",
17645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        b_first)) {
17655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pass = false;
17665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
17675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            it_b++;
17685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
17695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned attrib_type = get_format_type(it_a->second->format);
17705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned input_type = get_fundamental_type(vs, it_b->second.type_id);
17715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
177225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // Type checking
17735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (attrib_type != FORMAT_TYPE_UNDEFINED && input_type != FORMAT_TYPE_UNDEFINED && attrib_type != input_type) {
1774bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
1775bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
17764b5890faffa54a735782a6b0a628a991ddc86944Mike Weiblen                            "Attribute type of `%s` at location %d does not match vertex shader input type of `%s`",
1777bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            string_VkFormat(it_a->second->format), a_first, describe_type(vs, it_b->second.type_id).c_str())) {
17785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    pass = false;
17795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
17805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
17815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
178225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // OK!
17831730e0dd28b3abc660b4e4704cf6d414f7fd4ad6Chris Forbes            used = true;
17845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            it_b++;
17855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
17865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
17875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return pass;
17895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
17905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1791edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_fs_outputs_against_render_pass(debug_report_data *report_data, shader_module const *fs,
17928da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis                                                    spirv_inst_iter entrypoint, VkRenderPassCreateInfo const *rpci,
17938da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis                                                    uint32_t subpass_index) {
1794025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes    std::map<uint32_t, VkFormat> color_attachments;
17958da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis    auto subpass = rpci->pSubpasses[subpass_index];
17968da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis    for (auto i = 0u; i < subpass.colorAttachmentCount; ++i) {
1797d9da90d92748c37962766868f8b0354637672c2aTobin Ehlis        uint32_t attachment = subpass.pColorAttachments[i].attachment;
1798cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (attachment == VK_ATTACHMENT_UNUSED) continue;
1799d9da90d92748c37962766868f8b0354637672c2aTobin Ehlis        if (rpci->pAttachments[attachment].format != VK_FORMAT_UNDEFINED) {
1800d9da90d92748c37962766868f8b0354637672c2aTobin Ehlis            color_attachments[i] = rpci->pAttachments[attachment].format;
1801025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes        }
1802025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes    }
1803025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes
18045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool pass = true;
18055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
180625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // TODO: dual source blend index (spv::DecIndex, zero if not provided)
18075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18083a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    auto outputs = collect_interface_by_location(fs, entrypoint, spv::StorageClassOutput, false);
18095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1810025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes    auto it_a = outputs.begin();
1811025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes    auto it_b = color_attachments.begin();
18125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
181325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Walk attachment list and outputs together
1814025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes
1815025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes    while ((outputs.size() > 0 && it_a != outputs.end()) || (color_attachments.size() > 0 && it_b != color_attachments.end())) {
1816025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes        bool a_at_end = outputs.size() == 0 || it_a == outputs.end();
1817025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes        bool b_at_end = color_attachments.size() == 0 || it_b == color_attachments.end();
18185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1819025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes        if (!a_at_end && (b_at_end || it_a->first.first < it_b->first)) {
1820bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
1821bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",
1822d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen                        "fragment shader writes to output location %d with no matching attachment", it_a->first.first)) {
18235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pass = false;
18245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
1825025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            it_a++;
1826025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes        } else if (!b_at_end && (a_at_end || it_a->first.first > it_b->first)) {
1827bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
1828bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "Attachment %d not written by fragment shader", it_b->first)) {
18295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pass = false;
18305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
1831025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            it_b++;
18325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
1833025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            unsigned output_type = get_fundamental_type(fs, it_a->second.type_id);
1834025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            unsigned att_type = get_format_type(it_b->second);
18355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
183625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // Type checking
18375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (att_type != FORMAT_TYPE_UNDEFINED && output_type != FORMAT_TYPE_UNDEFINED && att_type != output_type) {
1838bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
1839bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
1840d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen                            "Attachment %d of type `%s` does not match fragment shader output type of `%s`", it_b->first,
1841bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            string_VkFormat(it_b->second), describe_type(fs, it_a->second.type_id).c_str())) {
18425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    pass = false;
18435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
18445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
18455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
184625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // OK!
1847025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            it_a++;
1848025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            it_b++;
18495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
18505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
18515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return pass;
18535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
18545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
185525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// For some analyses, we need to know about all ids referenced by the static call tree of a particular entrypoint. This is
185625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// important for identifying the set of shader resources actually used by an entrypoint, for example.
185725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// Note: we only explore parts of the image which might actually contain ids we care about for the above analyses.
185825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski//  - NOT the shader input/output interfaces.
185925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski//
186025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// TODO: The set of interesting opcodes here was determined by eyeballing the SPIRV spec. It might be worth
186125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// converting parts of this to be generated from the machine-readable spec instead.
18623a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbesstatic std::unordered_set<uint32_t> mark_accessible_ids(shader_module const *src, spirv_inst_iter entrypoint) {
18633a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    std::unordered_set<uint32_t> ids;
18645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_set<uint32_t> worklist;
18655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    worklist.insert(entrypoint.word(2));
18665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while (!worklist.empty()) {
18685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto id_iter = worklist.begin();
18695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto id = *id_iter;
18705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        worklist.erase(id_iter);
18715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto insn = src->get_def(id);
18735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn == src->end()) {
187425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // ID is something we didn't collect in build_def_index. that's OK -- we'll stumble across all kinds of things here
187525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // that we may not care about.
18765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            continue;
18775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
18785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
187925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Try to add to the output set
18805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!ids.insert(id).second) {
1881cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            continue;  // If we already saw this id, we don't want to walk it again.
18825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
18835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        switch (insn.opcode()) {
1885cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpFunction:
1886cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // Scan whole body of the function, enlisting anything interesting
1887cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                while (++insn, insn.opcode() != spv::OpFunctionEnd) {
1888cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    switch (insn.opcode()) {
1889cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpLoad:
1890cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicLoad:
1891cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicExchange:
1892cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicCompareExchange:
1893cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicCompareExchangeWeak:
1894cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicIIncrement:
1895cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicIDecrement:
1896cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicIAdd:
1897cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicISub:
1898cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicSMin:
1899cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicUMin:
1900cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicSMax:
1901cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicUMax:
1902cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicAnd:
1903cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicOr:
1904cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicXor:
1905cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            worklist.insert(insn.word(3));  // ptr
1906cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
1907cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpStore:
1908cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicStore:
1909cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            worklist.insert(insn.word(1));  // ptr
1910cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
1911cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAccessChain:
1912cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpInBoundsAccessChain:
1913cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            worklist.insert(insn.word(3));  // base ptr
1914cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
1915cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpSampledImage:
1916cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleImplicitLod:
1917cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleExplicitLod:
1918cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleDrefImplicitLod:
1919cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleDrefExplicitLod:
1920cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleProjImplicitLod:
1921cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleProjExplicitLod:
1922cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleProjDrefImplicitLod:
1923cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleProjDrefExplicitLod:
1924cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageFetch:
1925cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageGather:
1926cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageDrefGather:
1927cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageRead:
1928cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImage:
1929cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQueryFormat:
1930cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQueryOrder:
1931cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQuerySizeLod:
1932cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQuerySize:
1933cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQueryLod:
1934cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQueryLevels:
1935cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQuerySamples:
1936cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleImplicitLod:
1937cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleExplicitLod:
1938cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleDrefImplicitLod:
1939cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleDrefExplicitLod:
1940cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleProjImplicitLod:
1941cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleProjExplicitLod:
1942cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleProjDrefImplicitLod:
1943cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleProjDrefExplicitLod:
1944cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseFetch:
1945cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseGather:
1946cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseDrefGather:
1947cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageTexelPointer:
1948cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            worklist.insert(insn.word(3));  // Image or sampled image
1949cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
1950cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageWrite:
1951cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            worklist.insert(insn.word(1));  // Image -- different operand order to above
1952cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
1953cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpFunctionCall:
1954cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            for (uint32_t i = 3; i < insn.len(); i++) {
1955cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                worklist.insert(insn.word(i));  // fn itself, and all args
1956cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            }
1957cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
19585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1959cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpExtInst:
1960cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            for (uint32_t i = 5; i < insn.len(); i++) {
1961cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                worklist.insert(insn.word(i));  // Operands to ext inst
1962cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            }
1963cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
19645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
19655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
1966cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
19675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
19685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
19693a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
19703a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    return ids;
19715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
19725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1973edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_push_constant_block_against_pipeline(debug_report_data *report_data,
1974416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis                                                          std::vector<VkPushConstantRange> const *push_constant_ranges,
19755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                          shader_module const *src, spirv_inst_iter type,
19765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                          VkShaderStageFlagBits stage) {
19775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool pass = true;
19785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
197925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Strip off ptrs etc
19805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    type = get_struct_type(src, type, false);
19815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(type != src->end());
19825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
198325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Validate directly off the offsets. this isn't quite correct for arrays and matrices, but is a good first step.
198425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // TODO: arrays, matrices, weird sizes
19855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
19865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
19875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(3) == spv::DecorationOffset) {
19885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                unsigned offset = insn.word(4);
1989cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto size = 4;  // Bytes; TODO: calculate this based on the type
19905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
19915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                bool found_range = false;
1992416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis                for (auto const &range : *push_constant_ranges) {
19935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    if (range.offset <= offset && range.offset + range.size >= offset + size) {
19945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        found_range = true;
19955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
19965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        if ((range.stageFlags & stage) == 0) {
1997bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
1998bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        SHADER_CHECKER_PUSH_CONSTANT_NOT_ACCESSIBLE_FROM_STAGE, "SC",
19995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                        "Push constant range covering variable starting at "
20005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                        "offset %u not accessible from stage %s",
20015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                        offset, string_VkShaderStageFlagBits(stage))) {
20025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                pass = false;
20035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                            }
20045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        }
20055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        break;
20075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
20085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
20095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (!found_range) {
2011bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
2012bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                SHADER_CHECKER_PUSH_CONSTANT_OUT_OF_RANGE, "SC",
20135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                "Push constant range covering variable starting at "
20145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                "offset %u not declared in layout",
20155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                offset)) {
20165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        pass = false;
20175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
20185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
20195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
20205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
20215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
20225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return pass;
20245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
20255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2026edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_push_constant_usage(debug_report_data *report_data,
2027416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis                                         std::vector<VkPushConstantRange> const *push_constant_ranges, shader_module const *src,
20285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                         std::unordered_set<uint32_t> accessible_ids, VkShaderStageFlagBits stage) {
20295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool pass = true;
20305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto id : accessible_ids) {
20325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto def_insn = src->get_def(id);
20335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (def_insn.opcode() == spv::OpVariable && def_insn.word(3) == spv::StorageClassPushConstant) {
2034416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis            pass &= validate_push_constant_block_against_pipeline(report_data, push_constant_ranges, src,
2035416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis                                                                  src->get_def(def_insn.word(1)), stage);
20365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
20375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
20385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return pass;
20405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
20415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2042fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis// For given pipelineLayout verify that the set_layout_node at slot.first
2043fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis//  has the requested binding at slot.second and return ptr to that binding
2044bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic VkDescriptorSetLayoutBinding const *get_descriptor_binding(PIPELINE_LAYOUT_NODE const *pipelineLayout,
2045bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                  descriptor_slot_t slot) {
2046cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!pipelineLayout) return nullptr;
20475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2048cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (slot.first >= pipelineLayout->set_layouts.size()) return nullptr;
20495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2050416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis    return pipelineLayout->set_layouts[slot.first]->GetDescriptorSetLayoutBindingPtrFromBinding(slot.second);
20515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
20525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Check object status for selected flag state
205451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool validate_status(layer_data *dev_data, GLOBAL_CB_NODE *pNode, CBStatusFlags status_mask, VkFlags msg_flags,
20554f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                            const char *fail_msg, UNIQUE_VALIDATION_ERROR_CODE const msg_code) {
20563d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    if (!(pNode->status & status_mask)) {
20574f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes        char const *const message = validation_error_map[msg_code];
205851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        return log_msg(dev_data->report_data, msg_flags, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
20594f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                       reinterpret_cast<const uint64_t &>(pNode->commandBuffer), __LINE__, msg_code, "DS",
20604f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                       "command buffer object 0x%p: %s. %s.", pNode->commandBuffer, fail_msg, message);
20615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2062e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    return false;
20635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
20645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Retrieve pipeline node ptr for given pipeline object
206651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic PIPELINE_STATE *getPipelineState(layer_data const *dev_data, VkPipeline pipeline) {
206751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->pipelineMap.find(pipeline);
206851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->pipelineMap.end()) {
2069ea8349eeee76ae2859c10870fd8bd9e60309eb28Chris Forbes        return nullptr;
20705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2071ea8349eeee76ae2859c10870fd8bd9e60309eb28Chris Forbes    return it->second;
20725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
20735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20749a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisRENDER_PASS_STATE *GetRenderPassState(layer_data const *dev_data, VkRenderPass renderpass) {
207551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->renderPassMap.find(renderpass);
207651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->renderPassMap.end()) {
207716387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes        return nullptr;
207816387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes    }
2079fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    return it->second.get();
208016387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes}
208116387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes
20829a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisFRAMEBUFFER_STATE *GetFramebufferState(const layer_data *dev_data, VkFramebuffer framebuffer) {
208351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->frameBufferMap.find(framebuffer);
208451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->frameBufferMap.end()) {
2085f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes        return nullptr;
2086f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes    }
208704861caca7eb93a5241b164e8480bb93c826902cTobin Ehlis    return it->second.get();
2088f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes}
2089f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes
20909a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehliscvdescriptorset::DescriptorSetLayout const *GetDescriptorSetLayout(layer_data const *dev_data, VkDescriptorSetLayout dsLayout) {
209151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->descriptorSetLayoutMap.find(dsLayout);
209251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->descriptorSetLayoutMap.end()) {
209311f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes        return nullptr;
209411f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes    }
209511f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes    return it->second;
209611f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes}
209711f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes
209851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic PIPELINE_LAYOUT_NODE const *getPipelineLayout(layer_data const *dev_data, VkPipelineLayout pipeLayout) {
209951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->pipelineLayoutMap.find(pipeLayout);
210051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->pipelineLayoutMap.end()) {
21014a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes        return nullptr;
21024a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes    }
21034a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes    return &it->second;
21044a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes}
21054a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes
2106e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves// Return true if for a given PSO, the given state enum is dynamic, else return false
21074c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic bool isDynamic(const PIPELINE_STATE *pPipeline, const VkDynamicState state) {
21085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pPipeline && pPipeline->graphicsPipelineCI.pDynamicState) {
21095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < pPipeline->graphicsPipelineCI.pDynamicState->dynamicStateCount; i++) {
2110cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (state == pPipeline->graphicsPipelineCI.pDynamicState->pDynamicStates[i]) return true;
21115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
21125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2113e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    return false;
21145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
21155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
21165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Validate state stored as flags at time of draw call
21174f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayesstatic bool validate_draw_state_flags(layer_data *dev_data, GLOBAL_CB_NODE *pCB, const PIPELINE_STATE *pPipe, bool indexed,
21184f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                      UNIQUE_VALIDATION_ERROR_CODE const msg_code) {
21199c4006684a13db43f0dbc8d0015a9ef34872ca09Chris Forbes    bool result = false;
2120ca546210846c65808717f8875deae39bd227c240Tobin Ehlis    if (pPipe->graphicsPipelineCI.pInputAssemblyState &&
2121ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        ((pPipe->graphicsPipelineCI.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST) ||
2122ca546210846c65808717f8875deae39bd227c240Tobin Ehlis         (pPipe->graphicsPipelineCI.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP))) {
21233d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_LINE_WIDTH_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
21244f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic line width state not set for this command buffer", msg_code);
21253d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
212645824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves    if (pPipe->graphicsPipelineCI.pRasterizationState &&
212745824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves        (pPipe->graphicsPipelineCI.pRasterizationState->depthBiasEnable == VK_TRUE)) {
21283d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_DEPTH_BIAS_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
21294f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic depth bias state not set for this command buffer", msg_code);
21303d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
21313d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    if (pPipe->blendConstantsEnabled) {
21323d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_BLEND_CONSTANTS_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
21334f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic blend constants state not set for this command buffer", msg_code);
21343d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
213545824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves    if (pPipe->graphicsPipelineCI.pDepthStencilState &&
213645824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves        (pPipe->graphicsPipelineCI.pDepthStencilState->depthBoundsTestEnable == VK_TRUE)) {
21373d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_DEPTH_BOUNDS_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
21384f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic depth bounds state not set for this command buffer", msg_code);
21393d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
214045824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves    if (pPipe->graphicsPipelineCI.pDepthStencilState &&
214145824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves        (pPipe->graphicsPipelineCI.pDepthStencilState->stencilTestEnable == VK_TRUE)) {
21423d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_STENCIL_READ_MASK_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
21434f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic stencil read mask state not set for this command buffer", msg_code);
21443d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_STENCIL_WRITE_MASK_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
21454f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic stencil write mask state not set for this command buffer", msg_code);
21463d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_STENCIL_REFERENCE_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
21474f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic stencil reference state not set for this command buffer", msg_code);
21483d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
21491c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    if (indexed) {
21503d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_INDEX_BUFFER_BOUND, VK_DEBUG_REPORT_ERROR_BIT_EXT,
21514f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Index buffer object not bound to this command buffer when Indexed Draw attempted", msg_code);
21523d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
21534f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes
21545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
21555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
21565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
21575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Verify attachment reference compatibility according to spec
21585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  If one array is larger, treat missing elements of shorter array as VK_ATTACHMENT_UNUSED & other array much match this
21595ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski//  If both AttachmentReference arrays have requested index, check their corresponding AttachmentDescriptions
21605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//   to make sure that format and samples counts match.
21615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  If not, they are not compatible.
21625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic bool attachment_references_compatible(const uint32_t index, const VkAttachmentReference *pPrimary,
21635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                             const uint32_t primaryCount, const VkAttachmentDescription *pPrimaryAttachments,
21645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                             const VkAttachmentReference *pSecondary, const uint32_t secondaryCount,
21655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                             const VkAttachmentDescription *pSecondaryAttachments) {
2166e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis    // Check potential NULL cases first to avoid nullptr issues later
2167e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis    if (pPrimary == nullptr) {
2168e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis        if (pSecondary == nullptr) {
2169e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis            return true;
2170e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis        }
2171e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis        return false;
2172e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis    } else if (pSecondary == nullptr) {
2173e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis        return false;
2174e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis    }
2175cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (index >= primaryCount) {  // Check secondary as if primary is VK_ATTACHMENT_UNUSED
2176cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (VK_ATTACHMENT_UNUSED == pSecondary[index].attachment) return true;
2177cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    } else if (index >= secondaryCount) {  // Check primary as if secondary is VK_ATTACHMENT_UNUSED
2178cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (VK_ATTACHMENT_UNUSED == pPrimary[index].attachment) return true;
2179cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    } else {  // Format and sample count must match
21805ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski        if ((pPrimary[index].attachment == VK_ATTACHMENT_UNUSED) && (pSecondary[index].attachment == VK_ATTACHMENT_UNUSED)) {
21815ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski            return true;
21825ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski        } else if ((pPrimary[index].attachment == VK_ATTACHMENT_UNUSED) || (pSecondary[index].attachment == VK_ATTACHMENT_UNUSED)) {
21835ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski            return false;
21845ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski        }
21855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if ((pPrimaryAttachments[pPrimary[index].attachment].format ==
21865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis             pSecondaryAttachments[pSecondary[index].attachment].format) &&
21875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            (pPrimaryAttachments[pPrimary[index].attachment].samples ==
21885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis             pSecondaryAttachments[pSecondary[index].attachment].samples))
21895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return true;
21905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
21915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Format and sample counts didn't match
21925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return false;
21935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
2194a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis// TODO : Scrub verify_renderpass_compatibility() and validateRenderPassCompatibility() and unify them and/or share code
21958da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis// For given primary RenderPass object and secondry RenderPassCreateInfo, verify that they're compatible
219651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool verify_renderpass_compatibility(const layer_data *dev_data, const VkRenderPassCreateInfo *primaryRPCI,
21978da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis                                            const VkRenderPassCreateInfo *secondaryRPCI, string &errorMsg) {
21985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (primaryRPCI->subpassCount != secondaryRPCI->subpassCount) {
2199c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes        stringstream errorStr;
22005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        errorStr << "RenderPass for primary cmdBuffer has " << primaryRPCI->subpassCount
22015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                 << " subpasses but renderPass for secondary cmdBuffer has " << secondaryRPCI->subpassCount << " subpasses.";
22025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        errorMsg = errorStr.str();
22035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return false;
22045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
22055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t spIndex = 0;
22065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (spIndex = 0; spIndex < primaryRPCI->subpassCount; ++spIndex) {
22075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // For each subpass, verify that corresponding color, input, resolve & depth/stencil attachment references are compatible
22085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primaryColorCount = primaryRPCI->pSubpasses[spIndex].colorAttachmentCount;
22095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t secondaryColorCount = secondaryRPCI->pSubpasses[spIndex].colorAttachmentCount;
22105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t colorMax = std::max(primaryColorCount, secondaryColorCount);
22115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t cIdx = 0; cIdx < colorMax; ++cIdx) {
22125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!attachment_references_compatible(cIdx, primaryRPCI->pSubpasses[spIndex].pColorAttachments, primaryColorCount,
22135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                  primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pColorAttachments,
22145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                  secondaryColorCount, secondaryRPCI->pAttachments)) {
2215c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes                stringstream errorStr;
22165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorStr << "color attachments at index " << cIdx << " of subpass index " << spIndex << " are not compatible.";
22175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorMsg = errorStr.str();
22185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return false;
22195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else if (!attachment_references_compatible(cIdx, primaryRPCI->pSubpasses[spIndex].pResolveAttachments,
22205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                         primaryColorCount, primaryRPCI->pAttachments,
22215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                         secondaryRPCI->pSubpasses[spIndex].pResolveAttachments,
22225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                         secondaryColorCount, secondaryRPCI->pAttachments)) {
2223c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes                stringstream errorStr;
22245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorStr << "resolve attachments at index " << cIdx << " of subpass index " << spIndex << " are not compatible.";
22255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorMsg = errorStr.str();
22265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return false;
22275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
22285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
2229fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes
2230bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        if (!attachment_references_compatible(0, primaryRPCI->pSubpasses[spIndex].pDepthStencilAttachment, 1,
2231bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pDepthStencilAttachment,
2232fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes                                              1, secondaryRPCI->pAttachments)) {
2233c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes            stringstream errorStr;
2234fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes            errorStr << "depth/stencil attachments of subpass index " << spIndex << " are not compatible.";
2235fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes            errorMsg = errorStr.str();
2236fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes            return false;
2237fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes        }
2238fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes
22395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primaryInputCount = primaryRPCI->pSubpasses[spIndex].inputAttachmentCount;
22405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t secondaryInputCount = secondaryRPCI->pSubpasses[spIndex].inputAttachmentCount;
22415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t inputMax = std::max(primaryInputCount, secondaryInputCount);
22425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < inputMax; ++i) {
22435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!attachment_references_compatible(i, primaryRPCI->pSubpasses[spIndex].pInputAttachments, primaryColorCount,
22445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                  primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pInputAttachments,
22455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                  secondaryColorCount, secondaryRPCI->pAttachments)) {
2246c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes                stringstream errorStr;
22475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorStr << "input attachments at index " << i << " of subpass index " << spIndex << " are not compatible.";
22485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorMsg = errorStr.str();
22495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return false;
22505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
22515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
22525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
22535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return true;
22545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
22555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2256397d27da37095073c8b86f9ff5289d0a39ce486eTobin Ehlis// For given cvdescriptorset::DescriptorSet, verify that its Set is compatible w/ the setLayout corresponding to
2257397d27da37095073c8b86f9ff5289d0a39ce486eTobin Ehlis// pipelineLayout[layoutIndex]
225851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool verify_set_layout_compatibility(layer_data *dev_data, const cvdescriptorset::DescriptorSet *descriptor_set,
225969b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                                            PIPELINE_LAYOUT_NODE const *pipeline_layout, const uint32_t layoutIndex,
226069b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                                            string &errorMsg) {
2261416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis    auto num_sets = pipeline_layout->set_layouts.size();
22629b5d124aff50234cb0450e1b805baef577c90d83Tobin Ehlis    if (layoutIndex >= num_sets) {
2263c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes        stringstream errorStr;
226469b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis        errorStr << "VkPipelineLayout (" << pipeline_layout->layout << ") only contains " << num_sets
226569b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                 << " setLayouts corresponding to sets 0-" << num_sets - 1 << ", but you're attempting to bind set to index "
226669b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                 << layoutIndex;
22675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        errorMsg = errorStr.str();
22685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return false;
22695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2270416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis    auto layout_node = pipeline_layout->set_layouts[layoutIndex];
22711c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    return descriptor_set->IsCompatible(layout_node, &errorMsg);
22725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
22735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
22745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Validate that data for each specialization entry is fully contained within the buffer.
2275edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_specialization_offsets(debug_report_data *report_data, VkPipelineShaderStageCreateInfo const *info) {
2276e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool pass = true;
22775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
22785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkSpecializationInfo const *spec = info->pSpecializationInfo;
22795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
22805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (spec) {
22815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto i = 0u; i < spec->mapEntryCount; i++) {
22824f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes            // TODO: This is a good place for VALIDATION_ERROR_00589.
22835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (spec->pMapEntries[i].offset + spec->pMapEntries[i].size > spec->dataSize) {
22844f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
22854f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                            VALIDATION_ERROR_00590, "SC",
22865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                            "Specialization entry %u (for constant id %u) references memory outside provided "
22875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                            "specialization data (bytes %u.." PRINTF_SIZE_T_SPECIFIER "; " PRINTF_SIZE_T_SPECIFIER
22884f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                            " bytes provided). %s.",
22895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                            i, spec->pMapEntries[i].constantID, spec->pMapEntries[i].offset,
22904f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                            spec->pMapEntries[i].offset + spec->pMapEntries[i].size - 1, spec->dataSize,
22914f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                            validation_error_map[VALIDATION_ERROR_00590])) {
2292e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                    pass = false;
22935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
22945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
22955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
22965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
22975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
22985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return pass;
22995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
23005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2301bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool descriptor_type_match(shader_module const *module, uint32_t type_id, VkDescriptorType descriptor_type,
2302bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                  unsigned &descriptor_count) {
23035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto type = module->get_def(type_id);
23045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
23051b8c581791ac3c05d7829e04a2d8ecb964b8f2a6Chris Forbes    descriptor_count = 1;
23061b8c581791ac3c05d7829e04a2d8ecb964b8f2a6Chris Forbes
230725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Strip off any array or ptrs. Where we remove array levels, adjust the  descriptor count for each dimension.
23085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while (type.opcode() == spv::OpTypeArray || type.opcode() == spv::OpTypePointer) {
23097b892d2fc502b57d26dc9bff61b0f23cccc595fdChris Forbes        if (type.opcode() == spv::OpTypeArray) {
23107b892d2fc502b57d26dc9bff61b0f23cccc595fdChris Forbes            descriptor_count *= get_constant_value(module, type.word(3));
23117b892d2fc502b57d26dc9bff61b0f23cccc595fdChris Forbes            type = module->get_def(type.word(2));
2312bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        } else {
23137b892d2fc502b57d26dc9bff61b0f23cccc595fdChris Forbes            type = module->get_def(type.word(3));
23147b892d2fc502b57d26dc9bff61b0f23cccc595fdChris Forbes        }
23155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
23165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
23175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (type.opcode()) {
2318cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeStruct: {
2319cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            for (auto insn : *module) {
2320cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (insn.opcode() == spv::OpDecorate && insn.word(1) == type.word(1)) {
2321cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    if (insn.word(2) == spv::DecorationBlock) {
2322cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ||
2323cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                               descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
2324cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    } else if (insn.word(2) == spv::DecorationBufferBlock) {
2325cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ||
2326cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                               descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
2327cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    }
23285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
23295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
23305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2331cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Invalid
2332cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return false;
2333cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
23345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2335cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeSampler:
2336cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return descriptor_type == VK_DESCRIPTOR_TYPE_SAMPLER || descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
23375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2338cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeSampledImage:
2339cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) {
2340cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // Slight relaxation for some GLSL historical madness: samplerBuffer doesn't really have a sampler, and a texel
2341cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // buffer descriptor doesn't really provide one. Allow this slight mismatch.
2342cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto image_type = module->get_def(type.word(2));
2343cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto dim = image_type.word(3);
2344cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto sampled = image_type.word(7);
2345cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return dim == spv::DimBuffer && sampled == 1;
2346cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
2347cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
23485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2349cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeImage: {
2350cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Many descriptor types backing image types-- depends on dimension and whether the image will be used with a sampler.
2351cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // SPIRV for Vulkan requires that sampled be 1 or 2 -- leaving the decision to runtime is unacceptable.
2352cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            auto dim = type.word(3);
2353cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            auto sampled = type.word(7);
23545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2355cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (dim == spv::DimSubpassData) {
2356cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return descriptor_type == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
2357cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else if (dim == spv::DimBuffer) {
2358cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (sampled == 1) {
2359cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    return descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
2360cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                } else {
2361cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
2362cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
2363cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else if (sampled == 1) {
2364cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return descriptor_type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ||
2365cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                       descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
23665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else {
2367cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
23685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
23695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
23705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2371cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        // We shouldn't really see any other junk types -- but if we do, they're a mismatch.
2372cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
2373cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return false;  // Mismatch
23745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
23755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
23765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
23774110a6be7a8a287d459475926985f71c27d01298Chris Forbesstatic bool require_feature(debug_report_data *report_data, VkBool32 feature, char const *feature_name) {
2378a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    if (!feature) {
2379bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
2380cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    SHADER_CHECKER_FEATURE_NOT_ENABLED, "SC",
2381cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "Shader requires VkPhysicalDeviceFeatures::%s but is not "
2382cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "enabled on the device",
2383a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes                    feature_name)) {
2384a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes            return false;
2385a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes        }
2386a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    }
2387a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2388a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    return true;
2389a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes}
2390a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
239169f9a551bfb1fd5334950f9685c12c5adda23dfbChris Forbesstatic bool validate_shader_capabilities(debug_report_data *report_data, shader_module const *src,
239269f9a551bfb1fd5334950f9685c12c5adda23dfbChris Forbes                                         VkPhysicalDeviceFeatures const *enabledFeatures) {
2393e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool pass = true;
2394a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2395a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    for (auto insn : *src) {
2396a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes        if (insn.opcode() == spv::OpCapability) {
2397a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes            switch (insn.word(1)) {
2398cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityMatrix:
2399cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityShader:
2400cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityInputAttachment:
2401cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilitySampled1D:
2402cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityImage1D:
2403cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilitySampledBuffer:
2404cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityImageBuffer:
2405cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityImageQuery:
2406cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityDerivativeControl:
2407cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    // Always supported by a Vulkan 1.0 implementation -- no feature bits.
2408cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2409a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2410cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityGeometry:
2411cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->geometryShader, "geometryShader");
2412cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2413a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2414cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityTessellation:
2415cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->tessellationShader, "tessellationShader");
2416cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2417a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2418cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityFloat64:
2419cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderFloat64, "shaderFloat64");
2420cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2421a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2422cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityInt64:
2423cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderInt64, "shaderInt64");
2424cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2425a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2426cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityTessellationPointSize:
2427cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityGeometryPointSize:
2428cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderTessellationAndGeometryPointSize,
2429cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderTessellationAndGeometryPointSize");
2430cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2431a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2432cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityImageGatherExtended:
2433cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderImageGatherExtended, "shaderImageGatherExtended");
2434cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2435a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2436cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityStorageImageMultisample:
2437cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderStorageImageMultisample,
2438cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderStorageImageMultisample");
2439cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2440a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2441cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityUniformBufferArrayDynamicIndexing:
2442cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderUniformBufferArrayDynamicIndexing,
2443cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderUniformBufferArrayDynamicIndexing");
2444cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2445a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2446cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilitySampledImageArrayDynamicIndexing:
2447cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderSampledImageArrayDynamicIndexing,
2448cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderSampledImageArrayDynamicIndexing");
2449cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2450a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2451cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityStorageBufferArrayDynamicIndexing:
2452cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderStorageBufferArrayDynamicIndexing,
2453cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderStorageBufferArrayDynamicIndexing");
2454cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2455a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2456cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityStorageImageArrayDynamicIndexing:
2457cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderStorageImageArrayDynamicIndexing,
2458cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderStorageImageArrayDynamicIndexing");
2459cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2460a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2461cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityClipDistance:
2462cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderClipDistance, "shaderClipDistance");
2463cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2464a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2465cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityCullDistance:
2466cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderCullDistance, "shaderCullDistance");
2467cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2468a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2469cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityImageCubeArray:
2470cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->imageCubeArray, "imageCubeArray");
2471cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2472a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2473cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilitySampleRateShading:
2474cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->sampleRateShading, "sampleRateShading");
2475cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2476a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2477cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilitySparseResidency:
2478cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderResourceResidency, "shaderResourceResidency");
2479cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2480a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2481cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityMinLod:
2482cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderResourceMinLod, "shaderResourceMinLod");
2483cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2484a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2485cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilitySampledCubeArray:
2486cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->imageCubeArray, "imageCubeArray");
2487cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2488a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2489cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityImageMSArray:
2490cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderStorageImageMultisample,
2491cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderStorageImageMultisample");
2492cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2493a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2494cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityStorageImageExtendedFormats:
2495cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderStorageImageExtendedFormats,
2496cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderStorageImageExtendedFormats");
2497cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2498a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2499cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityInterpolationFunction:
2500cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->sampleRateShading, "sampleRateShading");
2501cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2502a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2503cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityStorageImageReadWithoutFormat:
2504cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderStorageImageReadWithoutFormat,
2505cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderStorageImageReadWithoutFormat");
2506cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2507a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2508cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityStorageImageWriteWithoutFormat:
2509cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->shaderStorageImageWriteWithoutFormat,
2510cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderStorageImageWriteWithoutFormat");
2511cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2512a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2513cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityMultiViewport:
2514cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    pass &= require_feature(report_data, enabledFeatures->multiViewport, "multiViewport");
2515cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2516a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2517cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                default:
2518cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
2519cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                SHADER_CHECKER_BAD_CAPABILITY, "SC", "Shader declares capability %u, not supported in Vulkan.",
2520cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                insn.word(1)))
2521cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        pass = false;
2522cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2523a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes            }
2524a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes        }
2525a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    }
2526a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2527a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    return pass;
2528a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes}
2529a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2530b2a61f3cd17c68887759817059fa1872f1e1464aChris Forbesstatic uint32_t descriptor_type_to_reqs(shader_module const *module, uint32_t type_id) {
25312aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes    auto type = module->get_def(type_id);
25322aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes
25332aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes    while (true) {
25342aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes        switch (type.opcode()) {
2535cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeArray:
2536cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeSampledImage:
2537cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                type = module->get_def(type.word(2));
2538cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
2539cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypePointer:
2540cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                type = module->get_def(type.word(3));
2541cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
2542cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeImage: {
2543cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto dim = type.word(3);
2544cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto arrayed = type.word(5);
2545cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto msaa = type.word(6);
2546cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski
2547cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                switch (dim) {
2548cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    case spv::Dim1D:
2549cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return arrayed ? DESCRIPTOR_REQ_VIEW_TYPE_1D_ARRAY : DESCRIPTOR_REQ_VIEW_TYPE_1D;
2550cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    case spv::Dim2D:
2551cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return (msaa ? DESCRIPTOR_REQ_MULTI_SAMPLE : DESCRIPTOR_REQ_SINGLE_SAMPLE) |
2552cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                               (arrayed ? DESCRIPTOR_REQ_VIEW_TYPE_2D_ARRAY : DESCRIPTOR_REQ_VIEW_TYPE_2D);
2553cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    case spv::Dim3D:
2554cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return DESCRIPTOR_REQ_VIEW_TYPE_3D;
2555cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    case spv::DimCube:
2556cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return arrayed ? DESCRIPTOR_REQ_VIEW_TYPE_CUBE_ARRAY : DESCRIPTOR_REQ_VIEW_TYPE_CUBE;
2557cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    case spv::DimSubpassData:
2558cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return msaa ? DESCRIPTOR_REQ_MULTI_SAMPLE : DESCRIPTOR_REQ_SINGLE_SAMPLE;
2559cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    default:  // buffer, etc.
2560cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return 0;
2561cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
25622aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes            }
2563cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
2564cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return 0;
25652aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes        }
25662aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes    }
2567b2a61f3cd17c68887759817059fa1872f1e1464aChris Forbes}
2568b2a61f3cd17c68887759817059fa1872f1e1464aChris Forbes
2569cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskistatic bool validate_pipeline_shader_stage(
2570cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    debug_report_data *report_data, VkPipelineShaderStageCreateInfo const *pStage, PIPELINE_STATE *pipeline,
2571cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    shader_module **out_module, spirv_inst_iter *out_entrypoint, VkPhysicalDeviceFeatures const *enabledFeatures,
2572cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    std::unordered_map<VkShaderModule, std::unique_ptr<shader_module>> const &shaderModuleMap) {
2573e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool pass = true;
257469f9a551bfb1fd5334950f9685c12c5adda23dfbChris Forbes    auto module_it = shaderModuleMap.find(pStage->module);
257569f9a551bfb1fd5334950f9685c12c5adda23dfbChris Forbes    auto module = *out_module = module_it->second.get();
257678be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
2577c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski    if (!module->has_valid_spirv) return pass;
2578c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski
257925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Find the entrypoint
258078be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    auto entrypoint = *out_entrypoint = find_entrypoint(module, pStage->pName, pStage->stage);
258178be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    if (entrypoint == module->end()) {
25824f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes        if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__, VALIDATION_ERROR_00510,
25834f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                    "SC", "No entrypoint found named `%s` for stage %s. %s.", pStage->pName,
25844f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                    string_VkShaderStageFlagBits(pStage->stage), validation_error_map[VALIDATION_ERROR_00510])) {
2585cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return false;  // no point continuing beyond here, any analysis is just going to be garbage.
258678be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        }
258778be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    }
258878be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
258925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Validate shader capabilities against enabled device features
2590557cdd5218accf51ca894a14b7c6eeeb733f5cbbChris Forbes    pass &= validate_shader_capabilities(report_data, module, enabledFeatures);
259178be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
259225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Mark accessible ids
25933a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    auto accessible_ids = mark_accessible_ids(module, entrypoint);
259478be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
259525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Validate descriptor set layout against what the entrypoint actually uses
25963a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    auto descriptor_uses = collect_interface_by_descriptor_slot(report_data, module, accessible_ids);
259778be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
25982e0eca3d6fad72a29ae072e3895e29a2d2d66476Tobin Ehlis    auto pipelineLayout = pipeline->pipeline_layout;
2599ed399f66e0512ef077d0e0a7cb903248726d2424Chris Forbes
26000cfa9c3a1747749777581684536218f83c3977a9Chris Forbes    pass &= validate_specialization_offsets(report_data, pStage);
2601416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis    pass &= validate_push_constant_usage(report_data, &pipelineLayout.push_constant_ranges, module, accessible_ids, pStage->stage);
260278be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
260325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Validate descriptor use
260478be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    for (auto use : descriptor_uses) {
260578be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        // While validating shaders capture which slots are used by the pipeline
2606bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto &reqs = pipeline->active_slots[use.first.first][use.first.second];
2607b2a61f3cd17c68887759817059fa1872f1e1464aChris Forbes        reqs = descriptor_req(reqs | descriptor_type_to_reqs(module, use.second.type_id));
260878be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
260925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Verify given pipelineLayout has requested setLayout with requested binding
2610c8268861aaa8f9c47920065d6323e4609e5081b0Tobin Ehlis        const auto &binding = get_descriptor_binding(&pipelineLayout, use.first);
261178be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        unsigned required_descriptor_count;
261278be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
261378be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        if (!binding) {
2614bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
2615bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        SHADER_CHECKER_MISSING_DESCRIPTOR, "SC",
261678be5018e238bd464b1f1c55138df277c0c18922Chris Forbes                        "Shader uses descriptor slot %u.%u (used as type `%s`) but not declared in pipeline layout",
261778be5018e238bd464b1f1c55138df277c0c18922Chris Forbes                        use.first.first, use.first.second, describe_type(module, use.second.type_id).c_str())) {
2618e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                pass = false;
261978be5018e238bd464b1f1c55138df277c0c18922Chris Forbes            }
262078be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        } else if (~binding->stageFlags & pStage->stage) {
2621bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
2622cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        SHADER_CHECKER_DESCRIPTOR_NOT_ACCESSIBLE_FROM_STAGE, "SC",
2623cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "Shader uses descriptor slot %u.%u (used "
2624cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "as type `%s`) but descriptor not "
2625cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "accessible from stage %s",
2626fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis                        use.first.first, use.first.second, describe_type(module, use.second.type_id).c_str(),
262778be5018e238bd464b1f1c55138df277c0c18922Chris Forbes                        string_VkShaderStageFlagBits(pStage->stage))) {
2628e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                pass = false;
262978be5018e238bd464b1f1c55138df277c0c18922Chris Forbes            }
2630bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        } else if (!descriptor_type_match(module, use.second.type_id, binding->descriptorType, required_descriptor_count)) {
2631557cdd5218accf51ca894a14b7c6eeeb733f5cbbChris Forbes            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
2632cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        SHADER_CHECKER_DESCRIPTOR_TYPE_MISMATCH, "SC",
2633cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "Type mismatch on descriptor slot "
2634cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "%u.%u (used as type `%s`) but "
2635cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "descriptor of type %s",
2636fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis                        use.first.first, use.first.second, describe_type(module, use.second.type_id).c_str(),
263778be5018e238bd464b1f1c55138df277c0c18922Chris Forbes                        string_VkDescriptorType(binding->descriptorType))) {
2638e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                pass = false;
263978be5018e238bd464b1f1c55138df277c0c18922Chris Forbes            }
264078be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        } else if (binding->descriptorCount < required_descriptor_count) {
2641557cdd5218accf51ca894a14b7c6eeeb733f5cbbChris Forbes            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
2642fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis                        SHADER_CHECKER_DESCRIPTOR_TYPE_MISMATCH, "SC",
264378be5018e238bd464b1f1c55138df277c0c18922Chris Forbes                        "Shader expects at least %u descriptors for binding %u.%u (used as type `%s`) but only %u provided",
264478be5018e238bd464b1f1c55138df277c0c18922Chris Forbes                        required_descriptor_count, use.first.first, use.first.second,
2645fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis                        describe_type(module, use.second.type_id).c_str(), binding->descriptorCount)) {
2646e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                pass = false;
264778be5018e238bd464b1f1c55138df277c0c18922Chris Forbes            }
264878be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        }
264978be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    }
265078be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
265125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Validate use of input attachments against subpass structure
2652c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes    if (pStage->stage == VK_SHADER_STAGE_FRAGMENT_BIT) {
26533a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes        auto input_attachment_uses = collect_interface_by_input_attachment_index(report_data, module, accessible_ids);
2654c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes
2655c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes        auto rpci = pipeline->render_pass_ci.ptr();
2656c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes        auto subpass = pipeline->graphicsPipelineCI.subpass;
2657c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes
2658c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes        for (auto use : input_attachment_uses) {
2659c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes            auto input_attachments = rpci->pSubpasses[subpass].pInputAttachments;
2660bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            auto index = (input_attachments && use.first < rpci->pSubpasses[subpass].inputAttachmentCount)
2661bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             ? input_attachments[use.first].attachment
2662bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             : VK_ATTACHMENT_UNUSED;
2663c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes
2664c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes            if (index == VK_ATTACHMENT_UNUSED) {
2665c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
2666c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes                            SHADER_CHECKER_MISSING_INPUT_ATTACHMENT, "SC",
2667bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "Shader consumes input attachment index %d but not provided in subpass", use.first)) {
2668c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes                    pass = false;
2669c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes                }
2670bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            } else if (get_format_type(rpci->pAttachments[index].format) != get_fundamental_type(module, use.second.type_id)) {
2671eeb9f6a27f1acc11e54080fb3bcda7b513b5c89fChris Forbes                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
2672eeb9f6a27f1acc11e54080fb3bcda7b513b5c89fChris Forbes                            SHADER_CHECKER_INPUT_ATTACHMENT_TYPE_MISMATCH, "SC",
2673bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "Subpass input attachment %u format of %s does not match type used in shader `%s`", use.first,
2674bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            string_VkFormat(rpci->pAttachments[index].format), describe_type(module, use.second.type_id).c_str())) {
2675eeb9f6a27f1acc11e54080fb3bcda7b513b5c89fChris Forbes                    pass = false;
2676eeb9f6a27f1acc11e54080fb3bcda7b513b5c89fChris Forbes                }
2677eeb9f6a27f1acc11e54080fb3bcda7b513b5c89fChris Forbes            }
2678c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes        }
2679c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes    }
2680c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes
268178be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    return pass;
268278be5018e238bd464b1f1c55138df277c0c18922Chris Forbes}
268378be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
2684a61b537fcb6a4f7b92cd217b3964ad7a48109da1Tobin Ehlis// Validate that the shaders used by the given pipeline and store the active_slots
2685a61b537fcb6a4f7b92cd217b3964ad7a48109da1Tobin Ehlis//  that are actually used by the pipeline into pPipeline->active_slots
2686cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskistatic bool validate_and_capture_pipeline_shader_state(
2687cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    debug_report_data *report_data, PIPELINE_STATE *pPipeline, VkPhysicalDeviceFeatures const *enabledFeatures,
2688cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    std::unordered_map<VkShaderModule, unique_ptr<shader_module>> const &shaderModuleMap) {
26896660d6f3e4e4c895063e8d99098162bd2f508b24Chris Forbes    auto pCreateInfo = pPipeline->graphicsPipelineCI.ptr();
26905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    int vertex_stage = get_shader_stage_id(VK_SHADER_STAGE_VERTEX_BIT);
26915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    int fragment_stage = get_shader_stage_id(VK_SHADER_STAGE_FRAGMENT_BIT);
26925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
26935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    shader_module *shaders[5];
26945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    memset(shaders, 0, sizeof(shaders));
26955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter entrypoints[5];
26965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    memset(entrypoints, 0, sizeof(entrypoints));
26975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkPipelineVertexInputStateCreateInfo const *vi = 0;
2698e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool pass = true;
26995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) {
27016660d6f3e4e4c895063e8d99098162bd2f508b24Chris Forbes        auto pStage = &pCreateInfo->pStages[i];
270278be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        auto stage_id = get_shader_stage_id(pStage->stage);
2703bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pass &= validate_pipeline_shader_stage(report_data, pStage, pPipeline, &shaders[stage_id], &entrypoints[stage_id],
270469f9a551bfb1fd5334950f9685c12c5adda23dfbChris Forbes                                               enabledFeatures, shaderModuleMap);
27055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
27065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2707d5365427feb4a6c16371ecb651afa37b89dabd96Chris Forbes    // if the shader stages are no good individually, cross-stage validation is pointless.
2708cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!pass) return false;
2709b7476f4c4998ae20e579bd2d134667b71acdbf91Chris Forbes
27105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    vi = pCreateInfo->pVertexInputState;
27115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (vi) {
2713e4be8c69231df45752686575f22168b6d0fc5687Chris Forbes        pass &= validate_vi_consistency(report_data, vi);
27145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
27155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2716c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski    if (shaders[vertex_stage] && shaders[vertex_stage]->has_valid_spirv) {
2717e4be8c69231df45752686575f22168b6d0fc5687Chris Forbes        pass &= validate_vi_against_vs_inputs(report_data, vi, shaders[vertex_stage], entrypoints[vertex_stage]);
27185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
27195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    int producer = get_shader_stage_id(VK_SHADER_STAGE_VERTEX_BIT);
27215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    int consumer = get_shader_stage_id(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
27225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while (!shaders[producer] && producer != fragment_stage) {
27245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        producer++;
27255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        consumer++;
27265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
27275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (; producer != fragment_stage && consumer <= fragment_stage; consumer++) {
27295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        assert(shaders[producer]);
2730c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski        if (shaders[consumer] && shaders[consumer]->has_valid_spirv && shaders[producer]->has_valid_spirv) {
2731bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            pass &= validate_interface_between_stages(report_data, shaders[producer], entrypoints[producer],
2732bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      &shader_stage_attribs[producer], shaders[consumer], entrypoints[consumer],
2733bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      &shader_stage_attribs[consumer]);
27345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            producer = consumer;
27365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
27375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
27385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2739c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski    if (shaders[fragment_stage] && shaders[fragment_stage]->has_valid_spirv) {
2740e4be8c69231df45752686575f22168b6d0fc5687Chris Forbes        pass &= validate_fs_outputs_against_render_pass(report_data, shaders[fragment_stage], entrypoints[fragment_stage],
27418da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis                                                        pPipeline->render_pass_ci.ptr(), pCreateInfo->subpass);
27425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
27435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return pass;
27455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
27465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27474c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic bool validate_compute_pipeline(debug_report_data *report_data, PIPELINE_STATE *pPipeline,
27484c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis                                      VkPhysicalDeviceFeatures const *enabledFeatures,
27494c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis                                      std::unordered_map<VkShaderModule, unique_ptr<shader_module>> const &shaderModuleMap) {
27506660d6f3e4e4c895063e8d99098162bd2f508b24Chris Forbes    auto pCreateInfo = pPipeline->computePipelineCI.ptr();
275103857e826cdc6e8d814137fb3245596ca1cb7bc7Chris Forbes
275203857e826cdc6e8d814137fb3245596ca1cb7bc7Chris Forbes    shader_module *module;
275303857e826cdc6e8d814137fb3245596ca1cb7bc7Chris Forbes    spirv_inst_iter entrypoint;
275403857e826cdc6e8d814137fb3245596ca1cb7bc7Chris Forbes
2755bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    return validate_pipeline_shader_stage(report_data, &pCreateInfo->stage, pPipeline, &module, &entrypoint, enabledFeatures,
2756bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                          shaderModuleMap);
275703857e826cdc6e8d814137fb3245596ca1cb7bc7Chris Forbes}
27585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Return Set node ptr for specified set or else NULL
27599a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehliscvdescriptorset::DescriptorSet *GetSetNode(const layer_data *dev_data, VkDescriptorSet set) {
276051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto set_it = dev_data->setMap.find(set);
276151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (set_it == dev_data->setMap.end()) {
27625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return NULL;
27635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2764104ab082916e41467ef60baaab7a5a8b2e02c59cTobin Ehlis    return set_it->second;
27655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
27665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2767eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young// For given pipeline, return number of MSAA samples, or one if MSAA disabled
27684c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic VkSampleCountFlagBits getNumSamples(PIPELINE_STATE const *pipe) {
2769ea8349eeee76ae2859c10870fd8bd9e60309eb28Chris Forbes    if (pipe->graphicsPipelineCI.pMultisampleState != NULL &&
2770ea8349eeee76ae2859c10870fd8bd9e60309eb28Chris Forbes        VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO == pipe->graphicsPipelineCI.pMultisampleState->sType) {
2771eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young        return pipe->graphicsPipelineCI.pMultisampleState->rasterizationSamples;
2772eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    }
2773eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    return VK_SAMPLE_COUNT_1_BIT;
2774eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young}
2775eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
2776bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic void list_bits(std::ostream &s, uint32_t bits) {
2777b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes    for (int i = 0; i < 32 && bits; i++) {
2778b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes        if (bits & (1 << i)) {
2779b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            s << i;
2780b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            bits &= ~(1 << i);
2781b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            if (bits) {
2782b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                s << ",";
2783b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            }
2784b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes        }
2785b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes    }
2786b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes}
2787b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes
2788eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young// Validate draw-time state related to the PSO
278951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool ValidatePipelineDrawtimeState(layer_data const *dev_data, LAST_BOUND_STATE const &state, const GLOBAL_CB_NODE *pCB,
27904c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis                                          PIPELINE_STATE const *pPipeline) {
2791eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    bool skip_call = false;
279229d196e071b2dc1db47702085469396f2b956820Chris Forbes
2793d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen    // Verify vertex binding
279429d196e071b2dc1db47702085469396f2b956820Chris Forbes    if (pPipeline->vertexBindingDescriptions.size() > 0) {
279529d196e071b2dc1db47702085469396f2b956820Chris Forbes        for (size_t i = 0; i < pPipeline->vertexBindingDescriptions.size(); i++) {
2796312129ec52e6249aa453e27e6be17a8dab1e98b8Tobin Ehlis            auto vertex_binding = pPipeline->vertexBindingDescriptions[i].binding;
2797312129ec52e6249aa453e27e6be17a8dab1e98b8Tobin Ehlis            if ((pCB->currentDrawData.buffers.size() < (vertex_binding + 1)) ||
2798312129ec52e6249aa453e27e6be17a8dab1e98b8Tobin Ehlis                (pCB->currentDrawData.buffers[vertex_binding] == VK_NULL_HANDLE)) {
2799cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                skip_call |=
280051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
2801cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            DRAWSTATE_VTX_INDEX_OUT_OF_BOUNDS, "DS",
2802cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "The Pipeline State Object (0x%" PRIxLEAST64
2803cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            ") expects that this Command Buffer's vertex binding Index %u "
2804cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "should be set via vkCmdBindVertexBuffers. This is because VkVertexInputBindingDescription struct "
2805cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "at index " PRINTF_SIZE_T_SPECIFIER " of pVertexBindingDescriptions has a binding value of %u.",
2806cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            (uint64_t)state.pipeline_state->pipeline, vertex_binding, i, vertex_binding);
280729d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
280829d196e071b2dc1db47702085469396f2b956820Chris Forbes        }
280929d196e071b2dc1db47702085469396f2b956820Chris Forbes    } else {
281058b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis        if (!pCB->currentDrawData.buffers.empty() && !pCB->vertex_buffer_used) {
281151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0,
28125c288f35b2eab0dab95d18768235fef6ffd69b30Tobin Ehlis                                 0, __LINE__, DRAWSTATE_VTX_INDEX_OUT_OF_BOUNDS, "DS",
2813226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                 "Vertex buffers are bound to command buffer (0x%p"
28145c288f35b2eab0dab95d18768235fef6ffd69b30Tobin Ehlis                                 ") but no vertex buffers are attached to this Pipeline State Object (0x%" PRIxLEAST64 ").",
2815226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                 pCB->commandBuffer, (uint64_t)state.pipeline_state->pipeline);
281629d196e071b2dc1db47702085469396f2b956820Chris Forbes        }
281729d196e071b2dc1db47702085469396f2b956820Chris Forbes    }
281829d196e071b2dc1db47702085469396f2b956820Chris Forbes    // If Viewport or scissors are dynamic, verify that dynamic count matches PSO count.
281929d196e071b2dc1db47702085469396f2b956820Chris Forbes    // Skip check if rasterization is disabled or there is no viewport.
282029d196e071b2dc1db47702085469396f2b956820Chris Forbes    if ((!pPipeline->graphicsPipelineCI.pRasterizationState ||
282129d196e071b2dc1db47702085469396f2b956820Chris Forbes         (pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable == VK_FALSE)) &&
282229d196e071b2dc1db47702085469396f2b956820Chris Forbes        pPipeline->graphicsPipelineCI.pViewportState) {
282329d196e071b2dc1db47702085469396f2b956820Chris Forbes        bool dynViewport = isDynamic(pPipeline, VK_DYNAMIC_STATE_VIEWPORT);
282429d196e071b2dc1db47702085469396f2b956820Chris Forbes        bool dynScissor = isDynamic(pPipeline, VK_DYNAMIC_STATE_SCISSOR);
2825b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes
282629d196e071b2dc1db47702085469396f2b956820Chris Forbes        if (dynViewport) {
2827b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            auto requiredViewportsMask = (1 << pPipeline->graphicsPipelineCI.pViewportState->viewportCount) - 1;
2828b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            auto missingViewportMask = ~pCB->viewportMask & requiredViewportsMask;
2829b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            if (missingViewportMask) {
2830b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                std::stringstream ss;
2831b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                ss << "Dynamic viewport(s) ";
2832b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                list_bits(ss, missingViewportMask);
2833d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen                ss << " are used by pipeline state object, but were not provided via calls to vkCmdSetViewport().";
283451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
2835bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                     __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", "%s", ss.str().c_str());
283629d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
283729d196e071b2dc1db47702085469396f2b956820Chris Forbes        }
2838b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes
283929d196e071b2dc1db47702085469396f2b956820Chris Forbes        if (dynScissor) {
2840b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            auto requiredScissorMask = (1 << pPipeline->graphicsPipelineCI.pViewportState->scissorCount) - 1;
2841b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            auto missingScissorMask = ~pCB->scissorMask & requiredScissorMask;
2842b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            if (missingScissorMask) {
2843b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                std::stringstream ss;
2844b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                ss << "Dynamic scissor(s) ";
2845b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                list_bits(ss, missingScissorMask);
2846d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen                ss << " are used by pipeline state object, but were not provided via calls to vkCmdSetScissor().";
284751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
2848bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                     __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", "%s", ss.str().c_str());
284929d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
285029d196e071b2dc1db47702085469396f2b956820Chris Forbes        }
285129d196e071b2dc1db47702085469396f2b956820Chris Forbes    }
285229d196e071b2dc1db47702085469396f2b956820Chris Forbes
285329d196e071b2dc1db47702085469396f2b956820Chris Forbes    // Verify that any MSAA request in PSO matches sample# in bound FB
285429d196e071b2dc1db47702085469396f2b956820Chris Forbes    // Skip the check if rasterization is disabled.
285529d196e071b2dc1db47702085469396f2b956820Chris Forbes    if (!pPipeline->graphicsPipelineCI.pRasterizationState ||
285629d196e071b2dc1db47702085469396f2b956820Chris Forbes        (pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable == VK_FALSE)) {
285729d196e071b2dc1db47702085469396f2b956820Chris Forbes        VkSampleCountFlagBits pso_num_samples = getNumSamples(pPipeline);
285829d196e071b2dc1db47702085469396f2b956820Chris Forbes        if (pCB->activeRenderPass) {
2859fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes            auto const render_pass_info = pCB->activeRenderPass->createInfo.ptr();
286029d196e071b2dc1db47702085469396f2b956820Chris Forbes            const VkSubpassDescription *subpass_desc = &render_pass_info->pSubpasses[pCB->activeSubpass];
286129d196e071b2dc1db47702085469396f2b956820Chris Forbes            uint32_t i;
286276957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes            unsigned subpass_num_samples = 0;
28630a7ed0466d3d3c6c71be07d66c200482d9a9d073Chris Forbes
286429d196e071b2dc1db47702085469396f2b956820Chris Forbes            for (i = 0; i < subpass_desc->colorAttachmentCount; i++) {
286576957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                auto attachment = subpass_desc->pColorAttachments[i].attachment;
286676957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                if (attachment != VK_ATTACHMENT_UNUSED)
286776957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                    subpass_num_samples |= (unsigned)render_pass_info->pAttachments[attachment].samples;
286829d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
28690a7ed0466d3d3c6c71be07d66c200482d9a9d073Chris Forbes
287076957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes            if (subpass_desc->pDepthStencilAttachment &&
287176957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                subpass_desc->pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
287276957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                auto attachment = subpass_desc->pDepthStencilAttachment->attachment;
287376957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                subpass_num_samples |= (unsigned)render_pass_info->pAttachments[attachment].samples;
287429d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
2875eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
28760dc3fd4e57b8531638781daa01a2fb5d1048a6fbJamie Madill            if (subpass_num_samples && static_cast<unsigned>(pso_num_samples) != subpass_num_samples) {
287729d196e071b2dc1db47702085469396f2b956820Chris Forbes                skip_call |=
287851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2879bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            reinterpret_cast<const uint64_t &>(pPipeline->pipeline), __LINE__, DRAWSTATE_NUM_SAMPLES_MISMATCH, "DS",
2880bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "Num samples mismatch! At draw-time in Pipeline (0x%" PRIxLEAST64
2881bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            ") with %u samples while current RenderPass (0x%" PRIxLEAST64 ") w/ %u samples!",
2882bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            reinterpret_cast<const uint64_t &>(pPipeline->pipeline), pso_num_samples,
2883bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            reinterpret_cast<const uint64_t &>(pCB->activeRenderPass->renderPass), subpass_num_samples);
2884eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young            }
288529d196e071b2dc1db47702085469396f2b956820Chris Forbes        } else {
288651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2887bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 reinterpret_cast<const uint64_t &>(pPipeline->pipeline), __LINE__, DRAWSTATE_NUM_SAMPLES_MISMATCH,
2888bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 "DS", "No active render pass found at draw-time in Pipeline (0x%" PRIxLEAST64 ")!",
288929d196e071b2dc1db47702085469396f2b956820Chris Forbes                                 reinterpret_cast<const uint64_t &>(pPipeline->pipeline));
2890eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young        }
2891eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    }
2892528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis    // Verify that PSO creation renderPass is compatible with active renderPass
2893528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis    if (pCB->activeRenderPass) {
2894528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis        std::string err_string;
2895a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        if ((pCB->activeRenderPass->renderPass != pPipeline->graphicsPipelineCI.renderPass) &&
289651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            !verify_renderpass_compatibility(dev_data, pCB->activeRenderPass->createInfo.ptr(), pPipeline->render_pass_ci.ptr(),
2897528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis                                             err_string)) {
2898528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis            // renderPass that PSO was created with must be compatible with active renderPass that PSO is being used with
2899528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis            skip_call |=
290051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2901528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis                        reinterpret_cast<const uint64_t &>(pPipeline->pipeline), __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE, "DS",
2902cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "At Draw time the active render pass (0x%" PRIxLEAST64
2903cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        ") is incompatible w/ gfx pipeline "
2904528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis                        "(0x%" PRIxLEAST64 ") that was created w/ render pass (0x%" PRIxLEAST64 ") due to: %s",
29056de0e43adfbd3c049252412d998524e7edbd3796Chris Forbes                        reinterpret_cast<uint64_t &>(pCB->activeRenderPass->renderPass),
29066de0e43adfbd3c049252412d998524e7edbd3796Chris Forbes                        reinterpret_cast<uint64_t const &>(pPipeline->pipeline),
2907528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis                        reinterpret_cast<const uint64_t &>(pPipeline->graphicsPipelineCI.renderPass), err_string.c_str());
2908528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis        }
2909c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes
2910c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes        if (pPipeline->graphicsPipelineCI.subpass != pCB->activeSubpass) {
2911c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes            skip_call |=
291251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2913c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes                        reinterpret_cast<uint64_t const &>(pPipeline->pipeline), __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE, "DS",
2914c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes                        "Pipeline was built for subpass %u but used in subpass %u", pPipeline->graphicsPipelineCI.subpass,
2915c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes                        pCB->activeSubpass);
2916c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes        }
2917528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis    }
291829d196e071b2dc1db47702085469396f2b956820Chris Forbes    // TODO : Add more checks here
291929d196e071b2dc1db47702085469396f2b956820Chris Forbes
2920eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    return skip_call;
2921eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young}
2922eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
29235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Validate overall state at the time of a draw call
292451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool ValidateDrawState(layer_data *dev_data, GLOBAL_CB_NODE *cb_node, const bool indexed,
29254f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                              const VkPipelineBindPoint bind_point, const char *function,
29264f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                              UNIQUE_VALIDATION_ERROR_CODE const msg_code) {
2927e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool result = false;
29281c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    auto const &state = cb_node->lastBound[bind_point];
29294c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    PIPELINE_STATE *pPipe = state.pipeline_state;
293022fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis    if (nullptr == pPipe) {
293122fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis        result |= log_msg(
293251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
293322fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis            DRAWSTATE_INVALID_PIPELINE, "DS",
293422fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis            "At Draw/Dispatch time no valid VkPipeline is bound! This is illegal. Please bind one with vkCmdBindPipeline().");
293522fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis        // Early return as any further checks below will be busted w/o a pipeline
2936cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (result) return true;
293722fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis    }
29383d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    // First check flag states
29391c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    if (VK_PIPELINE_BIND_POINT_GRAPHICS == bind_point)
294051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        result = validate_draw_state_flags(dev_data, cb_node, pPipe, indexed, msg_code);
29417a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis
29425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Now complete other state checks
294369b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis    if (VK_NULL_HANDLE != state.pipeline_layout.layout) {
294422fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis        string errorString;
294569b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis        auto pipeline_layout = pPipe->pipeline_layout;
2946169c4506062f06d6676eb4da3c9e0437d1d9d659Chris Forbes
29471c130ea631a82716dc7334de17767536525f2292Tobin Ehlis        for (const auto &set_binding_pair : pPipe->active_slots) {
29481c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            uint32_t setIndex = set_binding_pair.first;
294922fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis            // If valid set is not bound throw an error
295022fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis            if ((state.boundDescriptorSets.size() <= setIndex) || (!state.boundDescriptorSets[setIndex])) {
295151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                result |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
295222fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                                  DRAWSTATE_DESCRIPTOR_SET_NOT_BOUND, "DS",
2953bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                  "VkPipeline 0x%" PRIxLEAST64 " uses set #%u but that set is not bound.",
2954bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                  (uint64_t)pPipe->pipeline, setIndex);
295551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            } else if (!verify_set_layout_compatibility(dev_data, state.boundDescriptorSets[setIndex], &pipeline_layout, setIndex,
295669b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                                                        errorString)) {
295769b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                // Set is bound but not compatible w/ overlapping pipeline_layout from PSO
295871511c5a10533c910bfe62c3bcf58e2a4054e7acTobin Ehlis                VkDescriptorSet setHandle = state.boundDescriptorSets[setIndex]->GetSet();
295922fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                result |=
296051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
296122fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                            (uint64_t)setHandle, __LINE__, DRAWSTATE_PIPELINE_LAYOUTS_INCOMPATIBLE, "DS",
2962414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                            "VkDescriptorSet (0x%" PRIxLEAST64
2963414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                            ") bound as set #%u is not compatible with overlapping VkPipelineLayout 0x%" PRIxLEAST64 " due to: %s",
296469b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                            reinterpret_cast<uint64_t &>(setHandle), setIndex, reinterpret_cast<uint64_t &>(pipeline_layout.layout),
296569b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                            errorString.c_str());
2966cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else {  // Valid set is bound and layout compatible, validate that it's updated
296722fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                // Pull the set node
29681c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                cvdescriptorset::DescriptorSet *descriptor_set = state.boundDescriptorSets[setIndex];
2969aa21bc3b3c5c7adfeb488fc80bdcb339d63615b8Tobin Ehlis                // Gather active bindings
2970ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                std::unordered_set<uint32_t> active_bindings;
29711c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                for (auto binding : set_binding_pair.second) {
2972ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                    active_bindings.insert(binding.first);
2973aa21bc3b3c5c7adfeb488fc80bdcb339d63615b8Tobin Ehlis                }
297422fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                // Make sure set has been updated if it has no immutable samplers
297522fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                //  If it has immutable samplers, we'll flag error later as needed depending on binding
29761c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                if (!descriptor_set->IsUpdated()) {
2977ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                    for (auto binding : active_bindings) {
29781c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                        if (!descriptor_set->GetImmutableSamplerPtrFromBinding(binding)) {
297951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                            result |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
2980cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                              VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)descriptor_set->GetSet(),
2981cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                              __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS",
2982cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                              "Descriptor Set 0x%" PRIxLEAST64
2983cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                              " bound but was never updated. It is now being used to draw so "
2984cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                              "this will result in undefined behavior.",
2985cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                              (uint64_t)descriptor_set->GetSet());
2986fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis                        }
29875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
29885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
29897433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis                // Validate the draw-time state for this descriptor set
29907433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis                std::string err_str;
29911c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                if (!descriptor_set->ValidateDrawState(set_binding_pair.second, state.dynamicOffsets[setIndex], &err_str)) {
29921c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                    auto set = descriptor_set->GetSet();
299351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                    result |= log_msg(
299451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
299551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                        reinterpret_cast<const uint64_t &>(set), __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS",
299651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                        "Descriptor set 0x%" PRIxLEAST64 " encountered the following validation error at %s() time: %s",
299751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                        reinterpret_cast<const uint64_t &>(set), function, err_str.c_str());
29987433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis                }
29995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
300022fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis        }
300122fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis    }
3002eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
3003eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    // Check general pipeline state that needs to be validated at drawtime
300451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (VK_PIPELINE_BIND_POINT_GRAPHICS == bind_point) result |= ValidatePipelineDrawtimeState(dev_data, state, cb_node, pPipe);
3005eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
30065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
30075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
30085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
300951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void UpdateDrawState(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, const VkPipelineBindPoint bind_point) {
30101c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    auto const &state = cb_state->lastBound[bind_point];
3011ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis    PIPELINE_STATE *pPipe = state.pipeline_state;
3012ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis    if (VK_NULL_HANDLE != state.pipeline_layout.layout) {
30131c130ea631a82716dc7334de17767536525f2292Tobin Ehlis        for (const auto &set_binding_pair : pPipe->active_slots) {
30141c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            uint32_t setIndex = set_binding_pair.first;
3015ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis            // Pull the set node
30161c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            cvdescriptorset::DescriptorSet *descriptor_set = state.boundDescriptorSets[setIndex];
3017ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis            // Bind this set and its active descriptor resources to the command buffer
30181c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            descriptor_set->BindCommandBuffer(cb_state, set_binding_pair.second);
30197433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis            // For given active slots record updated images & buffers
30201c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            descriptor_set->GetStorageUpdates(set_binding_pair.second, &cb_state->updateBuffers, &cb_state->updateImages);
3021ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis        }
3022ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis    }
302358b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    if (pPipe->vertexBindingDescriptions.size() > 0) {
302458b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis        cb_state->vertex_buffer_used = true;
302558b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    }
3026ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis}
3027ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis
3028a27508babf63d50aea75883a3702979193c23683Mark Young// Validate HW line width capabilities prior to setting requested line width.
302951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool verifyLineWidth(layer_data *dev_data, DRAW_STATE_ERROR dsError, const uint64_t &target, float lineWidth) {
3030a27508babf63d50aea75883a3702979193c23683Mark Young    bool skip_call = false;
3031a27508babf63d50aea75883a3702979193c23683Mark Young
3032a27508babf63d50aea75883a3702979193c23683Mark Young    // First check to see if the physical device supports wide lines.
303351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if ((VK_FALSE == dev_data->enabled_features.wideLines) && (1.0f != lineWidth)) {
303451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, target, __LINE__,
3035cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             dsError, "DS",
3036cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "Attempt to set lineWidth to %f but physical device wideLines feature "
3037cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "not supported/enabled so lineWidth must be 1.0f!",
3038a27508babf63d50aea75883a3702979193c23683Mark Young                             lineWidth);
3039a27508babf63d50aea75883a3702979193c23683Mark Young    } else {
3040a27508babf63d50aea75883a3702979193c23683Mark Young        // Otherwise, make sure the width falls in the valid range.
304151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        if ((dev_data->phys_dev_properties.properties.limits.lineWidthRange[0] > lineWidth) ||
304251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            (dev_data->phys_dev_properties.properties.limits.lineWidthRange[1] < lineWidth)) {
304351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, target,
3044cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 __LINE__, dsError, "DS",
3045cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "Attempt to set lineWidth to %f but physical device limits line width "
3046cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "to between [%f, %f]!",
304751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                                 lineWidth, dev_data->phys_dev_properties.properties.limits.lineWidthRange[0],
304851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                                 dev_data->phys_dev_properties.properties.limits.lineWidthRange[1]);
3049a27508babf63d50aea75883a3702979193c23683Mark Young        }
3050a27508babf63d50aea75883a3702979193c23683Mark Young    }
3051a27508babf63d50aea75883a3702979193c23683Mark Young
3052a27508babf63d50aea75883a3702979193c23683Mark Young    return skip_call;
3053a27508babf63d50aea75883a3702979193c23683Mark Young}
3054a27508babf63d50aea75883a3702979193c23683Mark Young
30555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Verify that create state for a pipeline is valid
305651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool verifyPipelineCreateState(layer_data *dev_data, std::vector<PIPELINE_STATE *> pPipelines, int pipelineIndex) {
305783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
30585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
30594c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    PIPELINE_STATE *pPipeline = pPipelines[pipelineIndex];
30605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
30615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If create derivative bit is set, check that we've specified a base
30625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // pipeline correctly, and that the base pipeline was created to allow
30635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // derivatives.
30645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pPipeline->graphicsPipelineCI.flags & VK_PIPELINE_CREATE_DERIVATIVE_BIT) {
30654c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis        PIPELINE_STATE *pBasePipeline = nullptr;
30665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!((pPipeline->graphicsPipelineCI.basePipelineHandle != VK_NULL_HANDLE) ^
30675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis              (pPipeline->graphicsPipelineCI.basePipelineIndex != -1))) {
3068f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt            // This check is a superset of VALIDATION_ERROR_00526 and VALIDATION_ERROR_00528
306951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
307083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
307183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 "Invalid Pipeline CreateInfo: exactly one of base pipeline index and handle must be specified");
30725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (pPipeline->graphicsPipelineCI.basePipelineIndex != -1) {
30735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (pPipeline->graphicsPipelineCI.basePipelineIndex >= pipelineIndex) {
307483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                skip_call |=
307551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3076f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                            VALIDATION_ERROR_00518, "DS",
3077f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                            "Invalid Pipeline CreateInfo: base pipeline must occur earlier in array than derivative pipeline. %s",
3078f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                            validation_error_map[VALIDATION_ERROR_00518]);
30795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else {
30805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pBasePipeline = pPipelines[pPipeline->graphicsPipelineCI.basePipelineIndex];
30815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
30825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (pPipeline->graphicsPipelineCI.basePipelineHandle != VK_NULL_HANDLE) {
308351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            pBasePipeline = getPipelineState(dev_data, pPipeline->graphicsPipelineCI.basePipelineHandle);
30845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
30855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
30865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (pBasePipeline && !(pBasePipeline->graphicsPipelineCI.flags & VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT)) {
308751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
308883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
308983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 "Invalid Pipeline CreateInfo: base pipeline does not allow derivatives.");
30905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
30915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
30925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
30935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pPipeline->graphicsPipelineCI.pColorBlendState != NULL) {
3094fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis        const safe_VkPipelineColorBlendStateCreateInfo *color_blend_state = pPipeline->graphicsPipelineCI.pColorBlendState;
30959a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto const render_pass_info = GetRenderPassState(dev_data, pPipeline->graphicsPipelineCI.renderPass)->createInfo.ptr();
3096fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis        const VkSubpassDescription *subpass_desc = &render_pass_info->pSubpasses[pPipeline->graphicsPipelineCI.subpass];
3097fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis        if (color_blend_state->attachmentCount != subpass_desc->colorAttachmentCount) {
3098fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis            skip_call |= log_msg(
309951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
3100fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis                reinterpret_cast<const uint64_t &>(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_02109, "DS",
3101fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis                "vkCreateGraphicsPipelines(): Render pass (0x%" PRIxLEAST64
3102fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis                ") subpass %u has colorAttachmentCount of %u which doesn't match the pColorBlendState->attachmentCount of %u. %s",
3103fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis                reinterpret_cast<const uint64_t &>(pPipeline->graphicsPipelineCI.renderPass), pPipeline->graphicsPipelineCI.subpass,
3104fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis                subpass_desc->colorAttachmentCount, color_blend_state->attachmentCount,
3105fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis                validation_error_map[VALIDATION_ERROR_02109]);
3106fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis        }
310751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        if (!dev_data->enabled_features.independentBlend) {
31083d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis            if (pPipeline->attachments.size() > 1) {
310926c548826ff0f83d12c769b51e7d6f76d1265c0eChris Forbes                VkPipelineColorBlendAttachmentState *pAttachments = &pPipeline->attachments[0];
3110c7bd67f06427b08ba65cdf2dd529c8234beebdd5Mark Lobodzinski                for (size_t i = 1; i < pPipeline->attachments.size(); i++) {
311106811df0256552cd7da9d7297672af377463fc4aMark Mueller                    // Quoting the spec: "If [the independent blend] feature is not enabled, the VkPipelineColorBlendAttachmentState
311206811df0256552cd7da9d7297672af377463fc4aMark Mueller                    // settings for all color attachments must be identical." VkPipelineColorBlendAttachmentState contains
311306811df0256552cd7da9d7297672af377463fc4aMark Mueller                    // only attachment state, so memcmp is best suited for the comparison
311406811df0256552cd7da9d7297672af377463fc4aMark Mueller                    if (memcmp(static_cast<const void *>(pAttachments), static_cast<const void *>(&pAttachments[i]),
311506811df0256552cd7da9d7297672af377463fc4aMark Mueller                               sizeof(pAttachments[0]))) {
311651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
3117cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                             __LINE__, VALIDATION_ERROR_01532, "DS",
3118cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                             "Invalid Pipeline CreateInfo: If independent blend feature not "
3119cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                             "enabled, all elements of pAttachments must be identical. %s",
3120cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                             validation_error_map[VALIDATION_ERROR_01532]);
312106811df0256552cd7da9d7297672af377463fc4aMark Mueller                        break;
3122c7bd67f06427b08ba65cdf2dd529c8234beebdd5Mark Lobodzinski                    }
31235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
31245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
31255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
312651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        if (!dev_data->enabled_features.logicOp && (pPipeline->graphicsPipelineCI.pColorBlendState->logicOpEnable != VK_FALSE)) {
312783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |=
312851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3129f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                        VALIDATION_ERROR_01533, "DS",
3130f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                        "Invalid Pipeline CreateInfo: If logic operations feature not enabled, logicOpEnable must be VK_FALSE. %s",
3131f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                        validation_error_map[VALIDATION_ERROR_01533]);
31325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
31335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
31345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3135a61b537fcb6a4f7b92cd217b3964ad7a48109da1Tobin Ehlis    // Ensure the subpass index is valid. If not, then validate_and_capture_pipeline_shader_state
31365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // produces nonsense errors that confuse users. Other layers should already
31375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // emit errors for renderpass being invalid.
31389a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto renderPass = GetRenderPassState(dev_data, pPipeline->graphicsPipelineCI.renderPass);
3139fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    if (renderPass && pPipeline->graphicsPipelineCI.subpass >= renderPass->createInfo.subpassCount) {
314051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3141cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             VALIDATION_ERROR_02122, "DS",
3142cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "Invalid Pipeline CreateInfo State: Subpass index %u "
3143cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "is out of range for this renderpass (0..%u). %s",
3144f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             pPipeline->graphicsPipelineCI.subpass, renderPass->createInfo.subpassCount - 1,
3145f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             validation_error_map[VALIDATION_ERROR_02122]);
31465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
31475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
314851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (!GetDisables(dev_data)->shader_validation &&
314951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        !validate_and_capture_pipeline_shader_state(dev_data->report_data, pPipeline, &dev_data->enabled_features,
315051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                                                    dev_data->shaderModuleMap)) {
315183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis        skip_call = true;
31525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
315352156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes    // Each shader's stage must be unique
315452156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes    if (pPipeline->duplicate_shaders) {
315552156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes        for (uint32_t stage = VK_SHADER_STAGE_VERTEX_BIT; stage & VK_SHADER_STAGE_ALL_GRAPHICS; stage <<= 1) {
315652156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes            if (pPipeline->duplicate_shaders & stage) {
315751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
315883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                     __LINE__, DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
315983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                     "Invalid Pipeline CreateInfo State: Multiple shaders provided for stage %s",
316083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                     string_VkShaderStageFlagBits(VkShaderStageFlagBits(stage)));
316152156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes            }
316252156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes        }
316352156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes    }
31645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // VS is required
31655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (!(pPipeline->active_shaders & VK_SHADER_STAGE_VERTEX_BIT)) {
316651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3167f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             VALIDATION_ERROR_00532, "DS", "Invalid Pipeline CreateInfo State: Vertex Shader required. %s",
3168f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             validation_error_map[VALIDATION_ERROR_00532]);
31695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
31705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Either both or neither TC/TE shaders should be defined
3171f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    if ((pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) &&
3172f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt        !(pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)) {
317351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3174f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             VALIDATION_ERROR_00534, "DS",
3175f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             "Invalid Pipeline CreateInfo State: TE and TC shaders must be included or excluded as a pair. %s",
3176f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             validation_error_map[VALIDATION_ERROR_00534]);
3177f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    }
3178f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    if (!(pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) &&
3179f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt        (pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)) {
318051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3181f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             VALIDATION_ERROR_00535, "DS",
3182f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             "Invalid Pipeline CreateInfo State: TE and TC shaders must be included or excluded as a pair. %s",
3183f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             validation_error_map[VALIDATION_ERROR_00535]);
31845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
31855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Compute shaders should be specified independent of Gfx shaders
3186f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    if (pPipeline->active_shaders & VK_SHADER_STAGE_COMPUTE_BIT) {
318751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3188f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             VALIDATION_ERROR_00533, "DS",
3189f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             "Invalid Pipeline CreateInfo State: Do not specify Compute Shader for Gfx Pipeline. %s",
3190f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             validation_error_map[VALIDATION_ERROR_00533]);
31915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
31925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive topology is only valid for tessellation pipelines.
31935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Mismatching primitive topology and tessellation fails graphics pipeline creation.
31945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pPipeline->active_shaders & (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) &&
3195ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        (!pPipeline->graphicsPipelineCI.pInputAssemblyState ||
3196ca546210846c65808717f8875deae39bd227c240Tobin Ehlis         pPipeline->graphicsPipelineCI.pInputAssemblyState->topology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST)) {
319751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3198cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             VALIDATION_ERROR_02099, "DS",
3199cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "Invalid Pipeline CreateInfo State: "
3200cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST must be set as IA "
3201cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "topology for tessellation pipelines. %s",
3202f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             validation_error_map[VALIDATION_ERROR_02099]);
32035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
3204ca546210846c65808717f8875deae39bd227c240Tobin Ehlis    if (pPipeline->graphicsPipelineCI.pInputAssemblyState &&
3205ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        pPipeline->graphicsPipelineCI.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) {
32065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (~pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) {
320751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3208cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 VALIDATION_ERROR_02100, "DS",
3209cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "Invalid Pipeline CreateInfo State: "
3210cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive "
3211cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "topology is only valid for tessellation pipelines. %s",
3212f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                                 validation_error_map[VALIDATION_ERROR_02100]);
32135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
32145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
3215f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt
3216f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    if (pPipeline->graphicsPipelineCI.pTessellationState &&
3217f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt        ((pPipeline->graphicsPipelineCI.pTessellationState->patchControlPoints == 0) ||
3218f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt         (pPipeline->graphicsPipelineCI.pTessellationState->patchControlPoints >
321951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis          dev_data->phys_dev_properties.properties.limits.maxTessellationPatchSize))) {
322051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3221cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             VALIDATION_ERROR_01426, "DS",
3222cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "Invalid Pipeline CreateInfo State: "
3223cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive "
3224cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "topology used with patchControlPoints value %u."
3225cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             " patchControlPoints should be >0 and <=%u. %s",
3226f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             pPipeline->graphicsPipelineCI.pTessellationState->patchControlPoints,
322751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                             dev_data->phys_dev_properties.properties.limits.maxTessellationPatchSize,
3228f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             validation_error_map[VALIDATION_ERROR_01426]);
3229f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    }
3230f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt
32316b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen    // If a rasterization state is provided...
3232a27508babf63d50aea75883a3702979193c23683Mark Young    if (pPipeline->graphicsPipelineCI.pRasterizationState) {
32336b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen
32346b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen        // Make sure that the line width conforms to the HW.
3235a27508babf63d50aea75883a3702979193c23683Mark Young        if (!isDynamic(pPipeline, VK_DYNAMIC_STATE_LINE_WIDTH)) {
323651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            skip_call |= verifyLineWidth(dev_data, DRAWSTATE_INVALID_PIPELINE_CREATE_STATE,
32376de0e43adfbd3c049252412d998524e7edbd3796Chris Forbes                                         reinterpret_cast<uint64_t const &>(pPipeline->pipeline),
323883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                         pPipeline->graphicsPipelineCI.pRasterizationState->lineWidth);
3239a27508babf63d50aea75883a3702979193c23683Mark Young        }
32405dcdd90e54199dfeb29938a3a03d998397c22664Chris Forbes
32416b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen        // If rasterization is enabled...
32426b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen        if (pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable == VK_FALSE) {
32436b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen            auto subpass_desc = renderPass ? &renderPass->createInfo.pSubpasses[pPipeline->graphicsPipelineCI.subpass] : nullptr;
32446b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen
32456b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen            // If subpass uses a depth/stencil attachment, pDepthStencilState must be a pointer to a valid structure
32466b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen            if (subpass_desc && subpass_desc->pDepthStencilAttachment &&
32476b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen                subpass_desc->pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
32486b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen                if (!pPipeline->graphicsPipelineCI.pDepthStencilState) {
32496b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
32506b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen                                         VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, VALIDATION_ERROR_02115, "DS",
32516b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen                                         "Invalid Pipeline CreateInfo State: pDepthStencilState is NULL when rasterization is "
32526b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen                                         "enabled and subpass uses a depth/stencil attachment. %s",
32536b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen                                         validation_error_map[VALIDATION_ERROR_02115]);
32546b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen                }
32555dcdd90e54199dfeb29938a3a03d998397c22664Chris Forbes            }
3256326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen
3257326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen            // If subpass uses color attachments, pColorBlendState must be valid pointer
3258326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen            if (subpass_desc) {
3259326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                uint32_t color_attachment_count = 0;
3260326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                for (uint32_t i = 0; i < subpass_desc->colorAttachmentCount; ++i) {
3261326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                    if (subpass_desc->pColorAttachments[i].attachment != VK_ATTACHMENT_UNUSED) {
3262326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                        ++color_attachment_count;
3263326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                    }
3264326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                }
3265326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                if (color_attachment_count > 0 && pPipeline->graphicsPipelineCI.pColorBlendState == nullptr) {
3266326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
3267326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                                         VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, VALIDATION_ERROR_02116, "DS",
3268326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                                         "Invalid Pipeline CreateInfo State: pColorBlendState is NULL when rasterization is "
3269326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                                         "enabled and subpass uses color attachments. %s",
3270326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                                         validation_error_map[VALIDATION_ERROR_02116]);
3271326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                }
3272326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen            }
32735dcdd90e54199dfeb29938a3a03d998397c22664Chris Forbes        }
32745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
32756b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen
327683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
32775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
32785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
32795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Free the Pipeline nodes
328051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void deletePipelines(layer_data *dev_data) {
328151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (dev_data->pipelineMap.size() <= 0) return;
328251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    for (auto &pipe_map_pair : dev_data->pipelineMap) {
3283ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        delete pipe_map_pair.second;
32845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
328551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    dev_data->pipelineMap.clear();
32865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
32875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
32885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Block of code at start here specifically for managing/tracking DSs
32895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
32905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Return Pool node ptr for specified pool or else NULL
32919a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisDESCRIPTOR_POOL_STATE *GetDescriptorPoolState(const layer_data *dev_data, const VkDescriptorPool pool) {
3292bb7ea477706f90eb2a72887f652795bc79f60ddeTobin Ehlis    auto pool_it = dev_data->descriptorPoolMap.find(pool);
3293bb7ea477706f90eb2a72887f652795bc79f60ddeTobin Ehlis    if (pool_it == dev_data->descriptorPoolMap.end()) {
32945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return NULL;
32955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
3296bb7ea477706f90eb2a72887f652795bc79f60ddeTobin Ehlis    return pool_it->second;
32975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
32985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
32995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Validate that given set is valid and that it's not being used by an in-flight CmdBuffer
33005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// func_str is the name of the calling function
3301e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves// Return false if no errors occur
3302e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves// Return true if validation error occurs and callback returns true (to skip upcoming API call down the chain)
33030dcd0f7b37456e2e552d37094ba503c0d089b906Tobin Ehlisstatic bool validateIdleDescriptorSet(const layer_data *dev_data, VkDescriptorSet set, std::string func_str) {
3304cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.idle_descriptor_set) return false;
3305e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
33060dcd0f7b37456e2e552d37094ba503c0d089b906Tobin Ehlis    auto set_node = dev_data->setMap.find(set);
33070dcd0f7b37456e2e552d37094ba503c0d089b906Tobin Ehlis    if (set_node == dev_data->setMap.end()) {
33080dcd0f7b37456e2e552d37094ba503c0d089b906Tobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
33095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                             (uint64_t)(set), __LINE__, DRAWSTATE_DOUBLE_DESTROY, "DS",
3310414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                             "Cannot call %s() on descriptor set 0x%" PRIxLEAST64 " that has not been allocated.", func_str.c_str(),
33115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                             (uint64_t)(set));
33125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
33131c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis        // TODO : This covers various error cases so should pass error enum into this function and use passed in enum here
33145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (set_node->second->in_use.load()) {
33151c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis            skip_call |=
33160dcd0f7b37456e2e552d37094ba503c0d089b906Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
33171c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis                        (uint64_t)(set), __LINE__, VALIDATION_ERROR_00919, "DS",
33181c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis                        "Cannot call %s() on descriptor set 0x%" PRIxLEAST64 " that is in use by a command buffer. %s",
33191c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis                        func_str.c_str(), (uint64_t)(set), validation_error_map[VALIDATION_ERROR_00919]);
33205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
33215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
33225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
33235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
3324f80bf38f4fb3f177b3e1be11b7b1c5edcdbf7d9bChris Forbes
3325e6651096ed8f07840447783c66827cc16d659a49Tobin Ehlis// Remove set from setMap and delete the set
33269dd448578d59cb5ce692e833ba230783b30f3550Tobin Ehlisstatic void freeDescriptorSet(layer_data *dev_data, cvdescriptorset::DescriptorSet *descriptor_set) {
33279dd448578d59cb5ce692e833ba230783b30f3550Tobin Ehlis    dev_data->setMap.erase(descriptor_set->GetSet());
33289dd448578d59cb5ce692e833ba230783b30f3550Tobin Ehlis    delete descriptor_set;
33299dd448578d59cb5ce692e833ba230783b30f3550Tobin Ehlis}
33305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Free all DS Pools including their Sets & related sub-structs
33315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// NOTE : Calls to this function should be wrapped in mutex
333251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void deletePools(layer_data *dev_data) {
333351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (dev_data->descriptorPoolMap.size() <= 0) return;
333451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    for (auto ii = dev_data->descriptorPoolMap.begin(); ii != dev_data->descriptorPoolMap.end(); ++ii) {
3335c5f47f0a54e14c47d402aeabc6498d981ecda9ccTobin Ehlis        // Remove this pools' sets from setMap and delete them
3336cb9ce9e05b8e939d3da35c64997c70049877f4feTobin Ehlis        for (auto ds : (*ii).second->sets) {
333751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            freeDescriptorSet(dev_data, ds);
33385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
3339f13bee0887f3c3d1d597c82869864be3be836737Tobin Ehlis        (*ii).second->sets.clear();
33405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
334151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    dev_data->descriptorPoolMap.clear();
33425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
33435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
334451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void clearDescriptorPool(layer_data *dev_data, const VkDevice device, const VkDescriptorPool pool,
33455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                VkDescriptorPoolResetFlags flags) {
33469a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DESCRIPTOR_POOL_STATE *pPool = GetDescriptorPoolState(dev_data, pool);
3347de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    // TODO: validate flags
3348de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    // For every set off of this pool, clear it, remove from setMap, and free cvdescriptorset::DescriptorSet
3349de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    for (auto ds : pPool->sets) {
335051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        freeDescriptorSet(dev_data, ds);
3351de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    }
3352de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    pPool->sets.clear();
3353de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    // Reset available count for each type and available sets for this pool
3354de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    for (uint32_t i = 0; i < pPool->availableDescriptorTypeCount.size(); ++i) {
3355de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis        pPool->availableDescriptorTypeCount[i] = pPool->maxDescriptorTypeCount[i];
33565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
3357de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    pPool->availableSets = pPool->maxSets;
33585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
33595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
33605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// For given CB object, fetch associated CB Node from map
33619a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisGLOBAL_CB_NODE *GetCBNode(layer_data const *dev_data, const VkCommandBuffer cb) {
336251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->commandBufferMap.find(cb);
336351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->commandBufferMap.end()) {
33645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return NULL;
33655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
33665121a8dcacb23766ba4455b4eea429f0a3d62099Chris Forbes    return it->second;
33675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
33685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Free all CB Nodes
33695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// NOTE : Calls to this function should be wrapped in mutex
337051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void deleteCommandBuffers(layer_data *dev_data) {
337151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (dev_data->commandBufferMap.empty()) {
33725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return;
33735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
337451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    for (auto ii = dev_data->commandBufferMap.begin(); ii != dev_data->commandBufferMap.end(); ++ii) {
33755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        delete (*ii).second;
33765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
337751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    dev_data->commandBufferMap.clear();
33785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
33795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
338029f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis// If a renderpass is active, verify that the given command type is appropriate for current subpass state
338129f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlisbool ValidateCmdSubpassState(const layer_data *dev_data, const GLOBAL_CB_NODE *pCB, const CMD_TYPE cmd_type) {
3382cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!pCB->activeRenderPass) return false;
3383e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
3384d0d8e333806eaac08bdc87ddeff886dc2b0f09e7Tobin Ehlis    if (pCB->activeSubpassContents == VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS &&
3385d0d8e333806eaac08bdc87ddeff886dc2b0f09e7Tobin Ehlis        (cmd_type != CMD_EXECUTECOMMANDS && cmd_type != CMD_NEXTSUBPASS && cmd_type != CMD_ENDRENDERPASS)) {
33865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
33875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                             DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
33885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                             "Commands cannot be called in a subpass using secondary command buffers.");
33895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else if (pCB->activeSubpassContents == VK_SUBPASS_CONTENTS_INLINE && cmd_type == CMD_EXECUTECOMMANDS) {
33905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
33915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                             DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
33925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                             "vkCmdExecuteCommands() cannot be called in a subpass using inline commands.");
33935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
33945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
33955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
33965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
339751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool checkGraphicsBit(const layer_data *dev_data, VkQueueFlags flags, const char *name) {
33985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (!(flags & VK_QUEUE_GRAPHICS_BIT))
339951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
34005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                       DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
34015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                       "Cannot call %s on a command buffer allocated from a pool without graphics capabilities.", name);
34025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return false;
34035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
34045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
340551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool checkComputeBit(const layer_data *dev_data, VkQueueFlags flags, const char *name) {
34065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (!(flags & VK_QUEUE_COMPUTE_BIT))
340751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
34085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                       DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
34095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                       "Cannot call %s on a command buffer allocated from a pool without compute capabilities.", name);
34105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return false;
34115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
34125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
341351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool checkGraphicsOrComputeBit(const layer_data *dev_data, VkQueueFlags flags, const char *name) {
34145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (!((flags & VK_QUEUE_GRAPHICS_BIT) || (flags & VK_QUEUE_COMPUTE_BIT)))
341551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
34165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                       DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
3417e4d82c37d6c861b388dbc80297c18d6255858cb4Dave Houlton                       "Cannot call %s on a command buffer allocated from a pool without graphics or compute capabilities.", name);
34185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return false;
34195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
34205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3421ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinskistatic bool ReportInvalidCommandBuffer(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, const char *call_source) {
3422ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski    bool skip = false;
3423ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski    for (auto obj : cb_state->broken_bindings) {
3424ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        const char *type_str = object_type_to_string(obj.type);
3425ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        // Descriptor sets are a special case that can be either destroyed or updated to invalidate a CB
3426ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        const char *cause_str = (obj.type == VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT) ? "destroyed or updated" : "destroyed";
3427ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3428ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                        reinterpret_cast<uint64_t &>(cb_state->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
3429ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                        "You are adding %s to command buffer 0x%p that is invalid because bound %s 0x%" PRIxLEAST64 " was %s.",
3430ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                        call_source, cb_state->commandBuffer, type_str, obj.handle, cause_str);
3431ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski    }
3432ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski    return skip;
3433ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski}
3434ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski
3435623784ad78c8b77a78c4db613db974c12e5f5a43Mark Lobodzinski// Validate the given command being added to the specified cmd buffer, flagging errors if CB is not in the recording state or if
3436623784ad78c8b77a78c4db613db974c12e5f5a43Mark Lobodzinski// there's an issue with the Cmd ordering
3437946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinskibool ValidateCmd(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, const CMD_TYPE cmd, const char *caller_name) {
3438946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
3439946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    auto command_pool = GetCommandPoolNode(dev_data, cb_state->createInfo.commandPool);
3440946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (command_pool) {
3441946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        VkQueueFlags flags = dev_data->phys_dev_properties.queue_family_properties[command_pool->queueFamilyIndex].queueFlags;
34425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        switch (cmd) {
3443cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_BINDPIPELINE:
3444cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_BINDPIPELINEDELTA:
3445cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_BINDDESCRIPTORSETS:
3446cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_FILLBUFFER:
3447cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_CLEARCOLORIMAGE:
3448cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_SETEVENT:
3449cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_RESETEVENT:
3450cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_WAITEVENTS:
3451cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_BEGINQUERY:
3452cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_ENDQUERY:
3453cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_RESETQUERYPOOL:
3454cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_COPYQUERYPOOLRESULTS:
3455cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_WRITETIMESTAMP:
3456946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                skip |= checkGraphicsOrComputeBit(dev_data, flags, cmdTypeToString(cmd).c_str());
3457cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
3458cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_SETVIEWPORTSTATE:
3459cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_SETSCISSORSTATE:
3460cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_SETLINEWIDTHSTATE:
3461cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_SETDEPTHBIASSTATE:
3462cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_SETBLENDSTATE:
3463cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_SETDEPTHBOUNDSSTATE:
3464cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_SETSTENCILREADMASKSTATE:
3465cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_SETSTENCILWRITEMASKSTATE:
3466cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_SETSTENCILREFERENCESTATE:
3467cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_BINDINDEXBUFFER:
3468cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_BINDVERTEXBUFFER:
3469cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_DRAW:
3470cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_DRAWINDEXED:
3471cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_DRAWINDIRECT:
3472cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_DRAWINDEXEDINDIRECT:
3473cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_BLITIMAGE:
3474cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_CLEARATTACHMENTS:
3475cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_CLEARDEPTHSTENCILIMAGE:
3476cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_RESOLVEIMAGE:
3477cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_BEGINRENDERPASS:
3478cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_NEXTSUBPASS:
3479cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_ENDRENDERPASS:
3480946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                skip |= checkGraphicsBit(dev_data, flags, cmdTypeToString(cmd).c_str());
3481cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
3482cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_DISPATCH:
3483cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_DISPATCHINDIRECT:
3484946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                skip |= checkComputeBit(dev_data, flags, cmdTypeToString(cmd).c_str());
3485cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
3486cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_COPYBUFFER:
3487cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_COPYIMAGE:
3488cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_COPYBUFFERTOIMAGE:
3489cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_COPYIMAGETOBUFFER:
3490cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_CLONEIMAGEDATA:
3491cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_UPDATEBUFFER:
3492cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_PIPELINEBARRIER:
3493cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_EXECUTECOMMANDS:
3494cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case CMD_END:
3495cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
3496cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
3497cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
34985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
34995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
3500946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (cb_state->state != CB_RECORDING) {
3501946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        if (cb_state->state == CB_INVALID) {
3502946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            skip |= ReportInvalidCommandBuffer(dev_data, cb_state, caller_name);
3503ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        } else {
3504946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3505946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            reinterpret_cast<uint64_t &>(cb_state->commandBuffer), __LINE__, DRAWSTATE_NO_BEGIN_COMMAND_BUFFER,
3506946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            "DS", "You must call vkBeginCommandBuffer() before this call to %s", caller_name);
3507ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        }
35087651c2eb9fe152ba62921ed60454afd882357e2aTobin Ehlis    } else {
3509946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmdSubpassState(dev_data, cb_state, cmd);
35105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
3511946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    return skip;
35125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
351329f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis
35141ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlisvoid UpdateCmdBufferLastCmd(GLOBAL_CB_NODE *cb_state, const CMD_TYPE cmd) {
351529f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis    if (cb_state->state == CB_RECORDING) {
351629f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        cb_state->last_cmd = cmd;
351729f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis    }
351829f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis}
35197e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis// For given object struct return a ptr of BASE_NODE type for its wrapping struct
35207e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin EhlisBASE_NODE *GetStateStructPtrFromObject(layer_data *dev_data, VK_OBJECT object_struct) {
35217e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    BASE_NODE *base_ptr = nullptr;
35227e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    switch (object_struct.type) {
3523cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT: {
35249a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetSetNode(dev_data, reinterpret_cast<VkDescriptorSet &>(object_struct.handle));
3525cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3526cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3527cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT: {
35289a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetSamplerState(dev_data, reinterpret_cast<VkSampler &>(object_struct.handle));
3529cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3530cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3531cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT: {
35329a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetQueryPoolNode(dev_data, reinterpret_cast<VkQueryPool &>(object_struct.handle));
3533cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3534cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3535cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT: {
3536cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            base_ptr = getPipelineState(dev_data, reinterpret_cast<VkPipeline &>(object_struct.handle));
3537cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3538cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3539cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT: {
35409a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetBufferState(dev_data, reinterpret_cast<VkBuffer &>(object_struct.handle));
3541cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3542cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3543cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT: {
35449a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetBufferViewState(dev_data, reinterpret_cast<VkBufferView &>(object_struct.handle));
3545cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3546cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3547cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT: {
35489a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetImageState(dev_data, reinterpret_cast<VkImage &>(object_struct.handle));
3549cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3550cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3551cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT: {
35529a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetImageViewState(dev_data, reinterpret_cast<VkImageView &>(object_struct.handle));
3553cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3554cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3555cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT: {
35569a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetEventNode(dev_data, reinterpret_cast<VkEvent &>(object_struct.handle));
3557cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3558cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3559cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT: {
35609a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetDescriptorPoolState(dev_data, reinterpret_cast<VkDescriptorPool &>(object_struct.handle));
3561cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3562cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3563cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT: {
35649a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetCommandPoolNode(dev_data, reinterpret_cast<VkCommandPool &>(object_struct.handle));
3565cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3566cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3567cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT: {
35689a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetFramebufferState(dev_data, reinterpret_cast<VkFramebuffer &>(object_struct.handle));
3569cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3570cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3571cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT: {
35729a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetRenderPassState(dev_data, reinterpret_cast<VkRenderPass &>(object_struct.handle));
3573cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3574cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3575cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT: {
35769a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetMemObjInfo(dev_data, reinterpret_cast<VkDeviceMemory &>(object_struct.handle));
3577cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3578cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3579cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
3580cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // TODO : Any other objects to be handled here?
3581cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            assert(0);
3582cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3583bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis    }
35847e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    return base_ptr;
35857e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis}
35867e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis
35877e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis// Tie the VK_OBJECT to the cmd buffer which includes:
35887e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis//  Add object_binding to cmd buffer
35897e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis//  Add cb_binding to object
35907e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlisstatic void addCommandBufferBinding(std::unordered_set<GLOBAL_CB_NODE *> *cb_bindings, VK_OBJECT obj, GLOBAL_CB_NODE *cb_node) {
35917e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    cb_bindings->insert(cb_node);
35927e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    cb_node->object_bindings.insert(obj);
35937e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis}
35947e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis// For a given object, if cb_node is in that objects cb_bindings, remove cb_node
35957e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlisstatic void removeCommandBufferBinding(layer_data *dev_data, VK_OBJECT const *object, GLOBAL_CB_NODE *cb_node) {
35967e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    BASE_NODE *base_obj = GetStateStructPtrFromObject(dev_data, *object);
3597cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (base_obj) base_obj->cb_bindings.erase(cb_node);
3598bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis}
35995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Reset the command buffer state
36005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Maintain the createInfo and set state to CB_NEW, but clear all other state
3601400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlisstatic void resetCB(layer_data *dev_data, const VkCommandBuffer cb) {
3602400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis    GLOBAL_CB_NODE *pCB = dev_data->commandBufferMap[cb];
36035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
3604b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine        pCB->in_use.store(0);
3605347d4d3139a1e743ed85bd375c20fd35bbe68d74Chris Forbes        pCB->last_cmd = CMD_NONE;
36065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Reset CB state (note that createInfo is not cleared)
36075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->commandBuffer = cb;
36085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        memset(&pCB->beginInfo, 0, sizeof(VkCommandBufferBeginInfo));
36095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        memset(&pCB->inheritanceInfo, 0, sizeof(VkCommandBufferInheritanceInfo));
36105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->numCmds = 0;
36115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        memset(pCB->drawCount, 0, NUM_DRAW_TYPES * sizeof(uint64_t));
36125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->state = CB_NEW;
36135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->submitCount = 0;
36145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status = 0;
3615b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes        pCB->viewportMask = 0;
3616b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes        pCB->scissorMask = 0;
361793c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski
361872d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis        for (uint32_t i = 0; i < VK_PIPELINE_BIND_POINT_RANGE_SIZE; ++i) {
361972d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis            pCB->lastBound[i].reset();
362072d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis        }
362193c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski
36225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        memset(&pCB->activeRenderPassBeginInfo, 0, sizeof(pCB->activeRenderPassBeginInfo));
3623ee691f5c5fa87aac3750454d2bca2cb582e4e817Chris Forbes        pCB->activeRenderPass = nullptr;
36245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->activeSubpassContents = VK_SUBPASS_CONTENTS_INLINE;
36255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->activeSubpass = 0;
3626e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis        pCB->broken_bindings.clear();
36275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->waitedEvents.clear();
36285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->events.clear();
3629c7e6bc41aa9c6e5a677b138b9459b252cd3bedf2Mark Lobodzinski        pCB->writeEventsBeforeWait.clear();
36305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->waitedEventsBeforeQueryReset.clear();
36315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->queryToStateMap.clear();
36325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->activeQueries.clear();
36335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->startedQueries.clear();
3634abfafae4ec5d76e520916b03d196e474e972c949Michael Lentine        pCB->imageSubresourceMap.clear();
36355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->imageLayoutMap.clear();
36365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->eventToStageMap.clear();
36375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->drawData.clear();
36385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->currentDrawData.buffers.clear();
363958b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis        pCB->vertex_buffer_used = false;
36405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->primaryCommandBuffer = VK_NULL_HANDLE;
3641bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        // Make sure any secondaryCommandBuffers are removed from globalInFlight
3642bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        for (auto secondary_cb : pCB->secondaryCommandBuffers) {
3643bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis            dev_data->globalInFlightCmdBuffers.erase(secondary_cb);
3644bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        }
36455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->secondaryCommandBuffers.clear();
36467a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        pCB->updateImages.clear();
36477a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        pCB->updateBuffers.clear();
3648400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis        clear_cmd_buf_and_mem_references(dev_data, pCB);
3649b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        pCB->eventUpdates.clear();
3650d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        pCB->queryUpdates.clear();
365193c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski
3652bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis        // Remove object bindings
3653bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis        for (auto obj : pCB->object_bindings) {
3654bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis            removeCommandBufferBinding(dev_data, &obj, pCB);
3655bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis        }
3656a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis        pCB->object_bindings.clear();
365793c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski        // Remove this cmdBuffer's reference from each FrameBuffer's CB ref list
365893c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski        for (auto framebuffer : pCB->framebuffers) {
36599a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto fb_state = GetFramebufferState(dev_data, framebuffer);
3660cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (fb_state) fb_state->cb_bindings.erase(pCB);
366193c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski        }
366293c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski        pCB->framebuffers.clear();
36637003b38da5cc27a063af3c45080f3a35438283eeTobin Ehlis        pCB->activeFramebuffer = VK_NULL_HANDLE;
36645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
36655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
36665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
36675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Set PSO-related status bits for CB, including dynamic state set via PSO
36684c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic void set_cb_pso_status(GLOBAL_CB_NODE *pCB, const PIPELINE_STATE *pPipe) {
36695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Account for any dynamic state not set via this PSO
3670ca546210846c65808717f8875deae39bd227c240Tobin Ehlis    if (!pPipe->graphicsPipelineCI.pDynamicState ||
3671cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        !pPipe->graphicsPipelineCI.pDynamicState->dynamicStateCount) {  // All state is static
36724052946ae557337ff95f3725e879131b1c63f865Tobin Ehlis        pCB->status |= CBSTATUS_ALL_STATE_SET;
36735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
36745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // First consider all state on
36755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Then unset any state that's noted as dynamic in PSO
36765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Finally OR that into CB statemask
36774052946ae557337ff95f3725e879131b1c63f865Tobin Ehlis        CBStatusFlags psoDynStateMask = CBSTATUS_ALL_STATE_SET;
3678ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        for (uint32_t i = 0; i < pPipe->graphicsPipelineCI.pDynamicState->dynamicStateCount; i++) {
3679ca546210846c65808717f8875deae39bd227c240Tobin Ehlis            switch (pPipe->graphicsPipelineCI.pDynamicState->pDynamicStates[i]) {
3680cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_LINE_WIDTH:
3681cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_LINE_WIDTH_SET;
3682cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3683cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_DEPTH_BIAS:
3684cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_DEPTH_BIAS_SET;
3685cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3686cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_BLEND_CONSTANTS:
3687cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_BLEND_CONSTANTS_SET;
3688cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3689cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_DEPTH_BOUNDS:
3690cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_DEPTH_BOUNDS_SET;
3691cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3692cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK:
3693cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_STENCIL_READ_MASK_SET;
3694cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3695cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_STENCIL_WRITE_MASK:
3696cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_STENCIL_WRITE_MASK_SET;
3697cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3698cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_STENCIL_REFERENCE:
3699cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_STENCIL_REFERENCE_SET;
3700cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3701cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                default:
3702cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    // TODO : Flag error here
3703cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
37045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
37055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
37065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= psoDynStateMask;
37075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
37085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
37095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3710623784ad78c8b77a78c4db613db974c12e5f5a43Mark Lobodzinski// Flags validation error if the associated call is made inside a render pass. The apiName routine should ONLY be called outside a
3711623784ad78c8b77a78c4db613db974c12e5f5a43Mark Lobodzinski// render pass.
371251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisbool insideRenderPass(const layer_data *dev_data, GLOBAL_CB_NODE *pCB, const char *apiName, UNIQUE_VALIDATION_ERROR_CODE msgCode) {
3713e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool inside = false;
37145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB->activeRenderPass) {
371551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        inside = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3716ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                         (uint64_t)pCB->commandBuffer, __LINE__, msgCode, "DS",
3717ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                         "%s: It is invalid to issue this call inside an active render pass (0x%" PRIxLEAST64 "). %s", apiName,
3718ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                         (uint64_t)pCB->activeRenderPass->renderPass, validation_error_map[msgCode]);
37195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
37205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return inside;
37215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
37225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
37235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Flags validation error if the associated call is made outside a render pass. The apiName
37245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// routine should ONLY be called inside a render pass.
372551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisbool outsideRenderPass(const layer_data *dev_data, GLOBAL_CB_NODE *pCB, const char *apiName, UNIQUE_VALIDATION_ERROR_CODE msgCode) {
3726e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool outside = false;
37275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (((pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_PRIMARY) && (!pCB->activeRenderPass)) ||
37285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        ((pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY) && (!pCB->activeRenderPass) &&
37295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis         !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT))) {
373051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        outside = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3731ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                          (uint64_t)pCB->commandBuffer, __LINE__, msgCode, "DS",
3732ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                          "%s: This call must be issued inside an active render pass. %s", apiName, validation_error_map[msgCode]);
37335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
37345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return outside;
37355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
37365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3737f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbesstatic void init_core_validation(instance_layer_data *instance_data, const VkAllocationCallbacks *pAllocator) {
3738b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis    layer_debug_actions(instance_data->report_data, instance_data->logging_callback, pAllocator, "lunarg_core_validation");
37395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
37405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3741747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbesstatic void checkInstanceRegisterExtensions(const VkInstanceCreateInfo *pCreateInfo, instance_layer_data *instance_data) {
3742747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
3743747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_SURFACE_EXTENSION_NAME))
3744747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->surfaceExtensionEnabled = true;
3745747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_DISPLAY_EXTENSION_NAME))
3746747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->displayExtensionEnabled = true;
3747747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_ANDROID_KHR
3748747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_ANDROID_SURFACE_EXTENSION_NAME))
3749747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->androidSurfaceExtensionEnabled = true;
3750747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#endif
3751747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_MIR_KHR
3752747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_MIR_SURFACE_EXTENSION_NAME))
3753747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->mirSurfaceExtensionEnabled = true;
3754747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#endif
3755747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WAYLAND_KHR
3756747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME))
3757747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->waylandSurfaceExtensionEnabled = true;
3758747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#endif
3759747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WIN32_KHR
3760747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_WIN32_SURFACE_EXTENSION_NAME))
3761747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->win32SurfaceExtensionEnabled = true;
3762747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#endif
3763747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XCB_KHR
3764747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_XCB_SURFACE_EXTENSION_NAME))
3765747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->xcbSurfaceExtensionEnabled = true;
3766747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#endif
3767747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XLIB_KHR
3768747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_XLIB_SURFACE_EXTENSION_NAME))
3769747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->xlibSurfaceExtensionEnabled = true;
3770747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#endif
3771747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
3772747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
3773747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
3774bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
3775bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              VkInstance *pInstance) {
37765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkLayerInstanceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
37775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
37785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(chain_info->u.pLayerInfo);
37795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
37805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance");
3781cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (fpCreateInstance == NULL) return VK_ERROR_INITIALIZATION_FAILED;
37825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
37835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Advance the link info for the next element on the chain
37845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
37855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
37865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
3787cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (result != VK_SUCCESS) return result;
37885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
378956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(*pInstance), instance_layer_data_map);
379056a5ba3e60a723781945959ffc10e2e215350de5Chia-I Wu    instance_data->instance = *pInstance;
37919172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    layer_init_instance_dispatch_table(*pInstance, &instance_data->dispatch_table, fpGetInstanceProcAddr);
37929172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    instance_data->report_data = debug_report_create_instance(
37939172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes        &instance_data->dispatch_table, *pInstance, pCreateInfo->enabledExtensionCount, pCreateInfo->ppEnabledExtensionNames);
3794747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    checkInstanceRegisterExtensions(pCreateInfo, instance_data);
3795b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis    init_core_validation(instance_data, pAllocator);
3796825ac70f99460ccb9494d34f93d8ee7ec303e5deMark Lobodzinski
37975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    ValidateLayerOrdering(*pCreateInfo);
37985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
37995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
38005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
38015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
380225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// Hook DestroyInstance to remove tableInstanceMap entry
380389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL DestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
38045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODOSC : Shouldn't need any customization here
38055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dispatch_key key = get_dispatch_key(instance);
38065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TBD: Need any locking this early, in case this function is called at the
38075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // same time by more than one thread?
380856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(key, instance_layer_data_map);
38099172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    instance_data->dispatch_table.DestroyInstance(instance, pAllocator);
38105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3811b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::lock_guard<std::mutex> lock(global_lock);
38125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Clean up logging callback, if any
38139172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    while (instance_data->logging_callback.size() > 0) {
38149172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes        VkDebugReportCallbackEXT callback = instance_data->logging_callback.back();
38159172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes        layer_destroy_msg_callback(instance_data->report_data, callback, pAllocator);
38169172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes        instance_data->logging_callback.pop_back();
38175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
38185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
38199172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    layer_debug_report_destroy_instance(instance_data->report_data);
38205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data_map.erase(key);
38215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
38225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3823373469f006399d6b5204ee05db3b56beb168b36fMark Youngstatic void checkDeviceRegisterExtensions(const VkDeviceCreateInfo *pCreateInfo, VkDevice device) {
38245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t i;
3825bee1d36c54af112766d4e8552ad302f39290683aMark Lobodzinski    // TBD: Need any locking, in case this function is called at the same time by more than one thread?
382656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
38275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->device_extensions.wsi_enabled = false;
3828c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young    dev_data->device_extensions.wsi_display_swapchain_enabled = false;
3829bee1d36c54af112766d4e8552ad302f39290683aMark Lobodzinski    dev_data->device_extensions.nv_glsl_shader_enabled = false;
38305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
38315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
3832bee1d36c54af112766d4e8552ad302f39290683aMark Lobodzinski        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0) {
38335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->device_extensions.wsi_enabled = true;
3834bee1d36c54af112766d4e8552ad302f39290683aMark Lobodzinski        }
3835bee1d36c54af112766d4e8552ad302f39290683aMark Lobodzinski        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME) == 0) {
3836c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young            dev_data->device_extensions.wsi_display_swapchain_enabled = true;
3837bee1d36c54af112766d4e8552ad302f39290683aMark Lobodzinski        }
3838bee1d36c54af112766d4e8552ad302f39290683aMark Lobodzinski        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_NV_GLSL_SHADER_EXTENSION_NAME) == 0) {
3839bee1d36c54af112766d4e8552ad302f39290683aMark Lobodzinski            dev_data->device_extensions.nv_glsl_shader_enabled = true;
3840bee1d36c54af112766d4e8552ad302f39290683aMark Lobodzinski        }
38415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
38425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
38435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3844838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski// Verify that queue family has been properly requested
3845ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblenstatic bool ValidateRequestedQueueFamilyProperties(instance_layer_data *instance_data, VkPhysicalDevice gpu,
3846ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                                                   const VkDeviceCreateInfo *create_info) {
3847838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski    bool skip_call = false;
38489a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, gpu);
3849838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski    // First check is app has actually requested queueFamilyProperties
38504b293996aa6a9bd92ef1f0175eca4b0e8a9fd9fcChris Forbes    if (!physical_device_state) {
3851bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        skip_call |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
3852bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVLIMITS_MUST_QUERY_COUNT, "DL",
3853838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski                             "Invalid call to vkCreateDevice() w/o first calling vkEnumeratePhysicalDevices().");
38544b293996aa6a9bd92ef1f0175eca4b0e8a9fd9fcChris Forbes    } else if (QUERY_DETAILS != physical_device_state->vkGetPhysicalDeviceQueueFamilyPropertiesState) {
3855838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski        // TODO: This is not called out as an invalid use in the spec so make more informative recommendation.
38564b293996aa6a9bd92ef1f0175eca4b0e8a9fd9fcChris Forbes        skip_call |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
3857838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski                             VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVLIMITS_INVALID_QUEUE_CREATE_REQUEST,
3858838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski                             "DL", "Call to vkCreateDevice() w/o first calling vkGetPhysicalDeviceQueueFamilyProperties().");
3859838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski    } else {
3860838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski        // Check that the requested queue properties are valid
3861838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski        for (uint32_t i = 0; i < create_info->queueCreateInfoCount; i++) {
3862838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski            uint32_t requestedIndex = create_info->pQueueCreateInfos[i].queueFamilyIndex;
38637d8b6ab1b68c397da50bad43deb1fba389ebace7Chris Forbes            if (requestedIndex >= physical_device_state->queue_family_properties.size()) {
3864838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski                skip_call |= log_msg(
38654b293996aa6a9bd92ef1f0175eca4b0e8a9fd9fcChris Forbes                    instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0,
3866838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski                    __LINE__, DEVLIMITS_INVALID_QUEUE_CREATE_REQUEST, "DL",
3867838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski                    "Invalid queue create request in vkCreateDevice(). Invalid queueFamilyIndex %u requested.", requestedIndex);
3868838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski            } else if (create_info->pQueueCreateInfos[i].queueCount >
38697d8b6ab1b68c397da50bad43deb1fba389ebace7Chris Forbes                       physical_device_state->queue_family_properties[requestedIndex].queueCount) {
3870cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                skip_call |= log_msg(
3871cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0,
3872cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    __LINE__, DEVLIMITS_INVALID_QUEUE_CREATE_REQUEST, "DL",
3873cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "Invalid queue create request in vkCreateDevice(). QueueFamilyIndex %u only has %u queues, but "
3874cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "requested queueCount is %u.",
3875cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    requestedIndex, physical_device_state->queue_family_properties[requestedIndex].queueCount,
3876cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    create_info->pQueueCreateInfos[i].queueCount);
3877838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski            }
3878838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski        }
3879838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski    }
3880838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski    return skip_call;
3881838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski}
3882838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski
3883f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski// Verify that features have been queried and that they are available
3884bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool ValidateRequestedFeatures(instance_layer_data *dev_data, VkPhysicalDevice phys,
3885bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                      const VkPhysicalDeviceFeatures *requested_features) {
3886f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    bool skip_call = false;
3887f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
38889a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto phys_device_state = GetPhysicalDeviceState(dev_data, phys);
38893bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes    const VkBool32 *actual = reinterpret_cast<VkBool32 *>(&phys_device_state->features);
3890825ac70f99460ccb9494d34f93d8ee7ec303e5deMark Lobodzinski    const VkBool32 *requested = reinterpret_cast<const VkBool32 *>(requested_features);
3891f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    // TODO : This is a nice, compact way to loop through struct, but a bad way to report issues
3892f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    //  Need to provide the struct member name with the issue. To do that seems like we'll
3893f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    //  have to loop through each struct member which should be done w/ codegen to keep in synch.
3894f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    uint32_t errors = 0;
3895f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    uint32_t total_bools = sizeof(VkPhysicalDeviceFeatures) / sizeof(VkBool32);
3896f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    for (uint32_t i = 0; i < total_bools; i++) {
3897f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski        if (requested[i] > actual[i]) {
3898f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski            // TODO: Add index to struct member name helper to be able to include a feature name
3899cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            skip_call |=
3900cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0,
3901cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        __LINE__, DEVLIMITS_INVALID_FEATURE_REQUESTED, "DL",
3902cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "While calling vkCreateDevice(), requesting feature #%u in VkPhysicalDeviceFeatures struct, "
3903cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "which is not available on this device.",
3904cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        i);
3905f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski            errors++;
3906f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski        }
3907f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    }
39083bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes    if (errors && (UNCALLED == phys_device_state->vkGetPhysicalDeviceFeaturesState)) {
3909f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski        // If user didn't request features, notify them that they should
3910f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski        // TODO: Verify this against the spec. I believe this is an invalid use of the API and should return an error
3911bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
3912bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             0, __LINE__, DEVLIMITS_INVALID_FEATURE_REQUESTED, "DL",
3913bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             "You requested features that are unavailable on this device. You should first query feature "
3914bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             "availability by calling vkGetPhysicalDeviceFeatures().");
3915f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    }
3916f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    return skip_call;
3917f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski}
3918f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
391989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo,
392089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                            const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
392156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(gpu), instance_layer_data_map);
3922f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    bool skip_call = false;
3923f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
3924f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    // Check that any requested features are available
3925f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    if (pCreateInfo->pEnabledFeatures) {
392656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        skip_call |= ValidateRequestedFeatures(instance_data, gpu, pCreateInfo->pEnabledFeatures);
3927f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    }
392856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    skip_call |= ValidateRequestedQueueFamilyProperties(instance_data, gpu, pCreateInfo);
3929f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
39301d659b4113b77a95325df10d602a03f1e7abf8b7Mark Mueller    if (skip_call) {
39311d659b4113b77a95325df10d602a03f1e7abf8b7Mark Mueller        return VK_ERROR_VALIDATION_FAILED_EXT;
39321d659b4113b77a95325df10d602a03f1e7abf8b7Mark Mueller    }
39331d659b4113b77a95325df10d602a03f1e7abf8b7Mark Mueller
39345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkLayerDeviceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
39355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
39365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(chain_info->u.pLayerInfo);
39375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
39385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;
393956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(instance_data->instance, "vkCreateDevice");
39405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (fpCreateDevice == NULL) {
39415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return VK_ERROR_INITIALIZATION_FAILED;
39425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
39435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
39445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Advance the link info for the next element on the chain
39455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
39465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
39475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = fpCreateDevice(gpu, pCreateInfo, pAllocator, pDevice);
39485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result != VK_SUCCESS) {
39495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return result;
39505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
39515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3952b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
395356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(*pDevice), layer_data_map);
39545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
395556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    device_data->instance_data = instance_data;
39565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Setup device dispatch table
395756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_init_device_dispatch_table(*pDevice, &device_data->dispatch_table, fpGetDeviceProcAddr);
395856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    device_data->device = *pDevice;
3959ec85232c4d8d9ddf7d2ae57cb8203c5ab52c1106Mark Lobodzinski    // Save PhysicalDevice handle
396056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    device_data->physical_device = gpu;
39615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
396256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    device_data->report_data = layer_debug_report_create_device(instance_data->report_data, *pDevice);
3963373469f006399d6b5204ee05db3b56beb168b36fMark Young    checkDeviceRegisterExtensions(pCreateInfo, *pDevice);
39645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Get physical device limits for this device
396556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceProperties(gpu, &(device_data->phys_dev_properties.properties));
39665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t count;
396756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties(gpu, &count, nullptr);
396856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    device_data->phys_dev_properties.queue_family_properties.resize(count);
396956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties(
397056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        gpu, &count, &device_data->phys_dev_properties.queue_family_properties[0]);
39715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO: device limits should make sure these are compatible
39725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCreateInfo->pEnabledFeatures) {
397356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        device_data->enabled_features = *pCreateInfo->pEnabledFeatures;
39745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
397556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        memset(&device_data->enabled_features, 0, sizeof(VkPhysicalDeviceFeatures));
39765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
3977e47dbc3f3340fa177d877a67b2adb76a570027e5Mark Lobodzinski    // Store physical device properties and physical device mem limits into device layer_data structs
397856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceMemoryProperties(gpu, &device_data->phys_dev_mem_props);
397956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceProperties(gpu, &device_data->phys_dev_props);
3980b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
39815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
39825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    ValidateLayerOrdering(*pCreateInfo);
39835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
39845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
39855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
39865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
39875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// prototype
398889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL DestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) {
39895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODOSC : Shouldn't need any customization here
39903ec39aeb6d6f08fb1ee45f64f72543a710754c62Tobin Ehlis    bool skip = false;
39915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dispatch_key key = get_dispatch_key(device);
399256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(key, layer_data_map);
39935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Free all the memory
3994b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
39955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    deletePipelines(dev_data);
3996fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    dev_data->renderPassMap.clear();
39975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    deleteCommandBuffers(dev_data);
3998f13bee0887f3c3d1d597c82869864be3be836737Tobin Ehlis    // This will also delete all sets in the pool & remove them from setMap
39995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    deletePools(dev_data);
4000f13bee0887f3c3d1d597c82869864be3be836737Tobin Ehlis    // All sets should be removed
4001f13bee0887f3c3d1d597c82869864be3be836737Tobin Ehlis    assert(dev_data->setMap.empty());
4002a1e5173c89eb7f03e0434ad45ccd1471e722fa71Tobin Ehlis    for (auto del_layout : dev_data->descriptorSetLayoutMap) {
4003a1e5173c89eb7f03e0434ad45ccd1471e722fa71Tobin Ehlis        delete del_layout.second;
4004a1e5173c89eb7f03e0434ad45ccd1471e722fa71Tobin Ehlis    }
4005fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis    dev_data->descriptorSetLayoutMap.clear();
40065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->imageViewMap.clear();
40075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->imageMap.clear();
40085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->imageSubresourceMap.clear();
40095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->imageLayoutMap.clear();
40105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->bufferViewMap.clear();
40115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->bufferMap.clear();
40121344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis    // Queues persist until device is destroyed
40131344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis    dev_data->queueMap.clear();
40145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Report any memory leaks
40155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_debug_report_destroy_device(device);
4016b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
40175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
40185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#if DISPATCH_MAP_DEBUG
4019414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller    fprintf(stderr, "Device: 0x%p, key: 0x%p\n", device, key);
40205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#endif
40213ec39aeb6d6f08fb1ee45f64f72543a710754c62Tobin Ehlis    if (!skip) {
40224a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyDevice(device, pAllocator);
40233ec39aeb6d6f08fb1ee45f64f72543a710754c62Tobin Ehlis        layer_data_map.erase(key);
40245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
40255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
40265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
40275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic const VkExtensionProperties instance_extensions[] = {{VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION}};
40285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4029208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis// For given stage mask, if Geometry shader stage is on w/o GS being enabled, report geo_error_id
4030208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis//   and if Tessellation Control or Evaluation shader stages are on w/o TS being enabled, report tess_error_id
4031208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlisstatic bool ValidateStageMaskGsTsEnables(layer_data *dev_data, VkPipelineStageFlags stageMask, const char *caller,
4032208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                                         UNIQUE_VALIDATION_ERROR_CODE geo_error_id, UNIQUE_VALIDATION_ERROR_CODE tess_error_id) {
4033208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    bool skip = false;
4034208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    if (!dev_data->enabled_features.geometryShader && (stageMask & VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT)) {
4035208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
4036cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        geo_error_id, "DL",
4037cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "%s call includes a stageMask with VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT bit set when "
4038cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "device does not have geometryShader feature enabled. %s",
4039208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                        caller, validation_error_map[geo_error_id]);
4040208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    }
4041208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    if (!dev_data->enabled_features.tessellationShader &&
4042208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        (stageMask & (VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT | VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT))) {
4043208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
4044cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        tess_error_id, "DL",
4045cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "%s call includes a stageMask with VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT "
4046cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "and/or VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT bit(s) set when device "
4047cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "does not have tessellationShader feature enabled. %s",
4048208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                        caller, validation_error_map[tess_error_id]);
4049208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    }
4050208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    return skip;
4051208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis}
4052208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis
405351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour// Loop through bound objects and increment their in_use counts if increment parameter is true
405451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour// or flag an error if unknown objects are found
405551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic bool ValidateOrIncrementBoundObjects(layer_data *dev_data, GLOBAL_CB_NODE const *cb_node, bool increment) {
4056162dac96d3883e8fffaa1f988043f62c06662d2eTobin Ehlis    bool skip = false;
4057162dac96d3883e8fffaa1f988043f62c06662d2eTobin Ehlis    DRAW_STATE_ERROR error_code = DRAWSTATE_NONE;
4058162dac96d3883e8fffaa1f988043f62c06662d2eTobin Ehlis    BASE_NODE *base_obj = nullptr;
4059a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    for (auto obj : cb_node->object_bindings) {
4060a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis        switch (obj.type) {
4061cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT: {
40629a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                base_obj = GetSetNode(dev_data, reinterpret_cast<VkDescriptorSet &>(obj.handle));
4063cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_DESCRIPTOR_SET;
4064cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4065cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4066cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT: {
40679a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                base_obj = GetSamplerState(dev_data, reinterpret_cast<VkSampler &>(obj.handle));
4068cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_SAMPLER;
4069cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4070cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4071cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT: {
40729a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                base_obj = GetQueryPoolNode(dev_data, reinterpret_cast<VkQueryPool &>(obj.handle));
4073cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_QUERY_POOL;
4074cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4075cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4076cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT: {
4077cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                base_obj = getPipelineState(dev_data, reinterpret_cast<VkPipeline &>(obj.handle));
4078cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_PIPELINE;
4079cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4080cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4081cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT: {
40829a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                base_obj = GetBufferState(dev_data, reinterpret_cast<VkBuffer &>(obj.handle));
4083cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_BUFFER;
4084cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4085cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4086cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT: {
40879a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                base_obj = GetBufferViewState(dev_data, reinterpret_cast<VkBufferView &>(obj.handle));
4088cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_BUFFER_VIEW;
4089cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4090cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4091cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT: {
40929a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                base_obj = GetImageState(dev_data, reinterpret_cast<VkImage &>(obj.handle));
4093cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_IMAGE;
4094cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4095cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4096cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT: {
40979a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                base_obj = GetImageViewState(dev_data, reinterpret_cast<VkImageView &>(obj.handle));
4098cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_IMAGE_VIEW;
4099cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4100cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4101cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT: {
41029a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                base_obj = GetEventNode(dev_data, reinterpret_cast<VkEvent &>(obj.handle));
4103cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_EVENT;
4104cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4105cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4106cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT: {
41079a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                base_obj = GetDescriptorPoolState(dev_data, reinterpret_cast<VkDescriptorPool &>(obj.handle));
4108cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_DESCRIPTOR_POOL;
4109cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4110cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4111cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT: {
41129a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                base_obj = GetCommandPoolNode(dev_data, reinterpret_cast<VkCommandPool &>(obj.handle));
4113cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_COMMAND_POOL;
4114cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4115cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4116cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT: {
41179a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                base_obj = GetFramebufferState(dev_data, reinterpret_cast<VkFramebuffer &>(obj.handle));
4118cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_FRAMEBUFFER;
4119cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4120cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4121cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT: {
41229a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                base_obj = GetRenderPassState(dev_data, reinterpret_cast<VkRenderPass &>(obj.handle));
4123cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_RENDERPASS;
4124cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4125cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4126cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT: {
41279a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                base_obj = GetMemObjInfo(dev_data, reinterpret_cast<VkDeviceMemory &>(obj.handle));
4128cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                error_code = DRAWSTATE_INVALID_DEVICE_MEMORY;
4129cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4130cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4131cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
4132cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // TODO : Merge handling of other objects types into this code
4133cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4134a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis        }
413551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        if (base_obj && increment) {
413651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            base_obj->in_use.fetch_add(1);
413751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        } else if (!base_obj && !increment) {
4138162dac96d3883e8fffaa1f988043f62c06662d2eTobin Ehlis            skip |=
4139162dac96d3883e8fffaa1f988043f62c06662d2eTobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, obj.type, obj.handle, __LINE__, error_code, "DS",
4140162dac96d3883e8fffaa1f988043f62c06662d2eTobin Ehlis                        "Cannot submit cmd buffer using deleted %s 0x%" PRIx64 ".", object_type_to_string(obj.type), obj.handle);
4141162dac96d3883e8fffaa1f988043f62c06662d2eTobin Ehlis        }
4142a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    }
4143162dac96d3883e8fffaa1f988043f62c06662d2eTobin Ehlis    return skip;
4144a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis}
41455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Track which resources are in-flight by atomically incrementing their "in_use" count
414651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic void incrementResources(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
414751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    cb_node->submitCount++;
41489a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis    cb_node->in_use.fetch_add(1);
41499a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis    dev_data->globalInFlightCmdBuffers.insert(cb_node->commandBuffer);
4150a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
4151a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    // First Increment for all "generic" objects bound to cmd buffer, followed by special-case objects below
415251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    ValidateOrIncrementBoundObjects(dev_data, cb_node, true);
4153a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    // TODO : We should be able to remove the NULL look-up checks from the code below as long as
4154a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    //  all the corresponding cases are verified to cause CB_INVALID state and the CB_INVALID state
4155a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    //  should then be flagged prior to calling this function
41569a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis    for (auto drawDataElement : cb_node->drawData) {
41575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto buffer : drawDataElement.buffers) {
41589a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto buffer_state = GetBufferState(dev_data, buffer);
415951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            if (buffer_state) {
41605cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis                buffer_state->in_use.fetch_add(1);
41615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
41625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
41635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
41649a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis    for (auto event : cb_node->writeEventsBeforeWait) {
41659a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto event_state = GetEventNode(dev_data, event);
4166cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (event_state) event_state->write_in_use++;
4167c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    }
41685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
41695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4170b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis// Note: This function assumes that the global lock is held by the calling thread.
4171b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis// For the given queue, verify the queue state up to the given seq number.
4172b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis// Currently the only check is to make sure that if there are events to be waited on prior to
4173b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis//  a QueryReset, make sure that all such events have been signalled.
417436c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic bool VerifyQueueStateToSeq(layer_data *dev_data, QUEUE_STATE *queue, uint64_t seq) {
4175b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    bool skip = false;
4176b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    auto queue_seq = queue->seq;
417792b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis    std::unordered_map<VkQueue, uint64_t> other_queue_seqs;
417892b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis    auto sub_it = queue->submissions.begin();
4179b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    while (queue_seq < seq) {
418092b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis        for (auto &wait : sub_it->waitSemaphores) {
418192b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis            auto &last_seq = other_queue_seqs[wait.queue];
418292b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis            last_seq = std::max(last_seq, wait.seq);
418392b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis        }
418492b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis        for (auto cb : sub_it->cbs) {
41859a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto cb_node = GetCBNode(dev_data, cb);
4186b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis            if (cb_node) {
4187b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                for (auto queryEventsPair : cb_node->waitedEventsBeforeQueryReset) {
4188b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                    for (auto event : queryEventsPair.second) {
418992b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis                        if (dev_data->eventMap[event].needsSignaled) {
419092b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis                            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
4191b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                                            VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, 0, DRAWSTATE_INVALID_QUERY, "DS",
4192b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                                            "Cannot get query results on queryPool 0x%" PRIx64
4193b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                                            " with index %d which was guarded by unsignaled event 0x%" PRIx64 ".",
4194b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                                            (uint64_t)(queryEventsPair.first.pool), queryEventsPair.first.index, (uint64_t)(event));
4195b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                        }
4196b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                    }
4197b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine                }
4198b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine            }
4199b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine        }
420092b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis        sub_it++;
4201b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis        queue_seq++;
4202b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine    }
420392b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis    for (auto qs : other_queue_seqs) {
42049a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        skip |= VerifyQueueStateToSeq(dev_data, GetQueueState(dev_data, qs.first), qs.second);
420592b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis    }
4206b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    return skip;
4207b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis}
4208b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis
4209b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis// When the given fence is retired, verify outstanding queue operations through the point of the fence
4210b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlisstatic bool VerifyQueueStateToFence(layer_data *dev_data, VkFence fence) {
42119a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto fence_state = GetFenceNode(dev_data, fence);
4212b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    if (VK_NULL_HANDLE != fence_state->signaler.first) {
42139a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        return VerifyQueueStateToSeq(dev_data, GetQueueState(dev_data, fence_state->signaler.first), fence_state->signaler.second);
4214b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    }
4215b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    return false;
4216b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine}
42177d33205c3aa4aba751a2c07f956634aac616f916Chris Forbes
42187d33205c3aa4aba751a2c07f956634aac616f916Chris Forbes// TODO: nuke this completely.
4219b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine// Decrement cmd_buffer in_use and if it goes to 0 remove cmd_buffer from globalInFlightCmdBuffers
4220b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentinestatic inline void removeInFlightCmdBuffer(layer_data *dev_data, VkCommandBuffer cmd_buffer) {
4221b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine    // Pull it off of global list initially, but if we find it in any other queue list, add it back in
42229a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, cmd_buffer);
4223b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine    pCB->in_use.fetch_sub(1);
4224b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine    if (!pCB->in_use.load()) {
4225b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine        dev_data->globalInFlightCmdBuffers.erase(cmd_buffer);
4226b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine    }
4227b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine}
4228b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine
4229a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis// Decrement in-use count for objects bound to command buffer
42302f8cbf3b166e175174877a59929902e005953d6dTobin Ehlisstatic void DecrementBoundResources(layer_data *dev_data, GLOBAL_CB_NODE const *cb_node) {
423100e8ce2e6c1c191758f7b7c15eeaf350e5b4a3b6Tobin Ehlis    BASE_NODE *base_obj = nullptr;
4232a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    for (auto obj : cb_node->object_bindings) {
42337e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis        base_obj = GetStateStructPtrFromObject(dev_data, obj);
423400e8ce2e6c1c191758f7b7c15eeaf350e5b4a3b6Tobin Ehlis        if (base_obj) {
423500e8ce2e6c1c191758f7b7c15eeaf350e5b4a3b6Tobin Ehlis            base_obj->in_use.fetch_sub(1);
423600e8ce2e6c1c191758f7b7c15eeaf350e5b4a3b6Tobin Ehlis        }
4237a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    }
4238a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis}
4239da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes
424036c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic void RetireWorkOnQueue(layer_data *dev_data, QUEUE_STATE *pQueue, uint64_t seq) {
42419867daedbf52debc77d6568162ee21e071699b80Chris Forbes    std::unordered_map<VkQueue, uint64_t> otherQueueSeqs;
42429867daedbf52debc77d6568162ee21e071699b80Chris Forbes
42439867daedbf52debc77d6568162ee21e071699b80Chris Forbes    // Roll this queue forward, one submission at a time.
42449867daedbf52debc77d6568162ee21e071699b80Chris Forbes    while (pQueue->seq < seq) {
4245bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto &submission = pQueue->submissions.front();
42469867daedbf52debc77d6568162ee21e071699b80Chris Forbes
4247bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        for (auto &wait : submission.waitSemaphores) {
42489a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, wait.semaphore);
4249c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            if (pSemaphore) {
4250c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski                pSemaphore->in_use.fetch_sub(1);
4251c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            }
4252bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            auto &lastSeq = otherQueueSeqs[wait.queue];
42539867daedbf52debc77d6568162ee21e071699b80Chris Forbes            lastSeq = std::max(lastSeq, wait.seq);
4254da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes        }
4255cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes
4256bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        for (auto &semaphore : submission.signalSemaphores) {
42579a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
4258c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            if (pSemaphore) {
4259c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski                pSemaphore->in_use.fetch_sub(1);
4260c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            }
42619867daedbf52debc77d6568162ee21e071699b80Chris Forbes        }
4262cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes
42639867daedbf52debc77d6568162ee21e071699b80Chris Forbes        for (auto cb : submission.cbs) {
42649a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto cb_node = GetCBNode(dev_data, cb);
4265c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            if (!cb_node) {
4266c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski                continue;
4267c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            }
4268a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis            // First perform decrement on general case bound objects
42699a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            DecrementBoundResources(dev_data, cb_node);
42709a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            for (auto drawDataElement : cb_node->drawData) {
42719867daedbf52debc77d6568162ee21e071699b80Chris Forbes                for (auto buffer : drawDataElement.buffers) {
42729a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto buffer_state = GetBufferState(dev_data, buffer);
42735cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis                    if (buffer_state) {
42745cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis                        buffer_state->in_use.fetch_sub(1);
42759867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    }
42769867daedbf52debc77d6568162ee21e071699b80Chris Forbes                }
4277da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes            }
42789a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            for (auto event : cb_node->writeEventsBeforeWait) {
42799867daedbf52debc77d6568162ee21e071699b80Chris Forbes                auto eventNode = dev_data->eventMap.find(event);
42809867daedbf52debc77d6568162ee21e071699b80Chris Forbes                if (eventNode != dev_data->eventMap.end()) {
42819867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    eventNode->second.write_in_use--;
42829867daedbf52debc77d6568162ee21e071699b80Chris Forbes                }
42839867daedbf52debc77d6568162ee21e071699b80Chris Forbes            }
42849a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            for (auto queryStatePair : cb_node->queryToStateMap) {
42859867daedbf52debc77d6568162ee21e071699b80Chris Forbes                dev_data->queryToStateMap[queryStatePair.first] = queryStatePair.second;
42869867daedbf52debc77d6568162ee21e071699b80Chris Forbes            }
42879a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            for (auto eventStagePair : cb_node->eventToStageMap) {
42889867daedbf52debc77d6568162ee21e071699b80Chris Forbes                dev_data->eventMap[eventStagePair.first].stageMask = eventStagePair.second;
4289da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes            }
42900a32ed7bdf03e7bda914e03c0bfa6ebf400cdf5bMichael Lentine
42919867daedbf52debc77d6568162ee21e071699b80Chris Forbes            removeInFlightCmdBuffer(dev_data, cb);
42920a32ed7bdf03e7bda914e03c0bfa6ebf400cdf5bMichael Lentine        }
42939867daedbf52debc77d6568162ee21e071699b80Chris Forbes
42949a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto pFence = GetFenceNode(dev_data, submission.fence);
42959867daedbf52debc77d6568162ee21e071699b80Chris Forbes        if (pFence) {
42969867daedbf52debc77d6568162ee21e071699b80Chris Forbes            pFence->state = FENCE_RETIRED;
42970a32ed7bdf03e7bda914e03c0bfa6ebf400cdf5bMichael Lentine        }
42989867daedbf52debc77d6568162ee21e071699b80Chris Forbes
42999867daedbf52debc77d6568162ee21e071699b80Chris Forbes        pQueue->submissions.pop_front();
43009867daedbf52debc77d6568162ee21e071699b80Chris Forbes        pQueue->seq++;
4301b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
43029867daedbf52debc77d6568162ee21e071699b80Chris Forbes
43039867daedbf52debc77d6568162ee21e071699b80Chris Forbes    // Roll other queues forward to the highest seq we saw a wait for
43049867daedbf52debc77d6568162ee21e071699b80Chris Forbes    for (auto qs : otherQueueSeqs) {
43059a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        RetireWorkOnQueue(dev_data, GetQueueState(dev_data, qs.first), qs.second);
4306d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    }
43079867daedbf52debc77d6568162ee21e071699b80Chris Forbes}
4308651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
4309651d92815dfff917308137bb67aacccc4f60df86Chris Forbes// Submit a fence to a queue, delimiting previous fences and previous untracked
4310651d92815dfff917308137bb67aacccc4f60df86Chris Forbes// work by it.
431136c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic void SubmitFence(QUEUE_STATE *pQueue, FENCE_NODE *pFence, uint64_t submitCount) {
4312cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes    pFence->state = FENCE_INFLIGHT;
43139867daedbf52debc77d6568162ee21e071699b80Chris Forbes    pFence->signaler.first = pQueue->queue;
43149867daedbf52debc77d6568162ee21e071699b80Chris Forbes    pFence->signaler.second = pQueue->seq + pQueue->submissions.size() + submitCount;
4315b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine}
4316b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine
431751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic bool validateCommandBufferSimultaneousUse(layer_data *dev_data, GLOBAL_CB_NODE *pCB, int current_submit_count) {
43185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool skip_call = false;
431951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    if ((dev_data->globalInFlightCmdBuffers.count(pCB->commandBuffer) || current_submit_count > 1) &&
43205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
4321226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
4322f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                             0, __LINE__, VALIDATION_ERROR_00133, "DS",
4323f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                             "Command Buffer 0x%p is already in use and is not marked for simultaneous use. %s", pCB->commandBuffer,
4324f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                             validation_error_map[VALIDATION_ERROR_00133]);
43255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
43265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
43275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
43285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4329946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinskistatic bool validateCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, const char *call_source,
4330440bdd357701497c3442e3515f12ac1cfffc180aTony Barbour                                       int current_submit_count) {
4331c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis    bool skip = false;
4332cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.command_buffer_state) return skip;
43330a59acde4b40fde3bbfea5811d2abf2c85ca62f4Tobin Ehlis    // Validate ONE_TIME_SUBMIT_BIT CB is not being submitted more than once
4334946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if ((cb_state->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) &&
4335946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        (cb_state->submitCount + current_submit_count > 1)) {
4336c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
4337c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis                        __LINE__, DRAWSTATE_COMMAND_BUFFER_SINGLE_SUBMIT_VIOLATION, "DS",
4338226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "Commandbuffer 0x%p was begun w/ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT "
4339c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis                        "set, but has been submitted 0x%" PRIxLEAST64 " times.",
4340946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        cb_state->commandBuffer, cb_state->submitCount + current_submit_count);
43410a59acde4b40fde3bbfea5811d2abf2c85ca62f4Tobin Ehlis    }
43425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Validate that cmd buffers have been updated
4343946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (CB_RECORDED != cb_state->state) {
4344946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        if (CB_INVALID == cb_state->state) {
4345946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            skip |= ReportInvalidCommandBuffer(dev_data, cb_state, call_source);
4346cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        } else {  // Flag error for using CB w/o vkEndCommandBuffer() called
4347c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
4348946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            (uint64_t)(cb_state->commandBuffer), __LINE__, DRAWSTATE_NO_END_COMMAND_BUFFER, "DS",
4349946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            "You must call vkEndCommandBuffer() on command buffer 0x%p before this call to %s!",
4350946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            cb_state->commandBuffer, call_source);
43515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
43525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
4353c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis    return skip;
43545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
43555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
435651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic bool validateResources(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
435751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    bool skip_call = false;
435851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
435951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    skip_call |= ValidateOrIncrementBoundObjects(dev_data, cb_node, false);
436051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    // TODO : We should be able to remove the NULL look-up checks from the code below as long as
436151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    //  all the corresponding cases are verified to cause CB_INVALID state and the CB_INVALID state
436251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    //  should then be flagged prior to calling this function
436351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    for (auto drawDataElement : cb_node->drawData) {
436451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        for (auto buffer : drawDataElement.buffers) {
436551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            auto buffer_state = GetBufferState(dev_data, buffer);
436651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            if (!buffer_state) {
436751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
436851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                                     (uint64_t)(buffer), __LINE__, DRAWSTATE_INVALID_BUFFER, "DS",
436951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                                     "Cannot submit cmd buffer using deleted buffer 0x%" PRIx64 ".", (uint64_t)(buffer));
437051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            }
437151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        }
437251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    }
437351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    return skip_call;
437451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour}
437551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
43767bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski// Validate that queueFamilyIndices of primary command buffers match this queue
43777bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski// Secondary command buffers were previously validated in vkCmdExecuteCommands().
43787bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinskistatic bool validateQueueFamilyIndices(layer_data *dev_data, GLOBAL_CB_NODE *pCB, VkQueue queue) {
43797bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski    bool skip_call = false;
43809a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pPool = GetCommandPoolNode(dev_data, pCB->createInfo.commandPool);
43819a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto queue_state = GetQueueState(dev_data, queue);
43827bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
438336c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlis    if (pPool && queue_state && (pPool->queueFamilyIndex != queue_state->queueFamilyIndex)) {
43847bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
4385f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                             reinterpret_cast<uint64_t>(pCB->commandBuffer), __LINE__, VALIDATION_ERROR_00139, "DS",
4386f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                             "vkQueueSubmit: Primary command buffer 0x%p created in queue family %d is being submitted on queue "
4387f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                             "0x%p from queue family %d. %s",
4388f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                             pCB->commandBuffer, pPool->queueFamilyIndex, queue, queue_state->queueFamilyIndex,
4389f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                             validation_error_map[VALIDATION_ERROR_00139]);
43907bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski    }
43917bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
43927bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski    return skip_call;
43937bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski}
43947bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
439551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic bool validatePrimaryCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB, int current_submit_count) {
43965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Track in-use for resources off of primary and any secondary CBs
439783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
4398a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
4399a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes    // If USAGE_SIMULTANEOUS_USE_BIT not set then CB cannot already be executing
4400a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes    // on device
440151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    skip_call |= validateCommandBufferSimultaneousUse(dev_data, pCB, current_submit_count);
4402a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
440351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    skip_call |= validateResources(dev_data, pCB);
4404a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
44055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (!pCB->secondaryCommandBuffers.empty()) {
44065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto secondaryCmdBuffer : pCB->secondaryCommandBuffers) {
44079a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            GLOBAL_CB_NODE *pSubCB = GetCBNode(dev_data, secondaryCmdBuffer);
440851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            skip_call |= validateResources(dev_data, pSubCB);
44094c665b29a9d2906a378417546c7fc6436731d07fTobin Ehlis            if ((pSubCB->primaryCommandBuffer != pCB->commandBuffer) &&
44104c665b29a9d2906a378417546c7fc6436731d07fTobin Ehlis                !(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
4411f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                log_msg(
4412f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
4413f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    __LINE__, VALIDATION_ERROR_00135, "DS",
4414f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    "Commandbuffer 0x%p was submitted with secondary buffer 0x%p but that buffer has subsequently been bound to "
4415f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    "primary cmd buffer 0x%p and it does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set. %s",
4416f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    pCB->commandBuffer, secondaryCmdBuffer, pSubCB->primaryCommandBuffer,
4417f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    validation_error_map[VALIDATION_ERROR_00135]);
44185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
44195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
44205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
4421a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
442251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    skip_call |= validateCommandBufferState(dev_data, pCB, "vkQueueSubmit()", current_submit_count);
4423a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
442483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
44255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
44265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4427bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool ValidateFenceForSubmit(layer_data *dev_data, FENCE_NODE *pFence) {
442883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
442981c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes
4430651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    if (pFence) {
4431cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes        if (pFence->state == FENCE_INFLIGHT) {
4432f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen            // TODO: opportunities for VALIDATION_ERROR_00127, VALIDATION_ERROR_01647, VALIDATION_ERROR_01953
443383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
443483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 (uint64_t)(pFence->fence), __LINE__, DRAWSTATE_INVALID_FENCE, "DS",
443583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 "Fence 0x%" PRIx64 " is already in use by another submission.", (uint64_t)(pFence->fence));
4436a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        }
443781c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes
4438cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes        else if (pFence->state == FENCE_RETIRED) {
4439f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen            // TODO: opportunities for VALIDATION_ERROR_00126, VALIDATION_ERROR_01646, VALIDATION_ERROR_01953
444083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |=
444183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
444283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                        reinterpret_cast<uint64_t &>(pFence->fence), __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM",
444383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                        "Fence 0x%" PRIxLEAST64 " submitted in SIGNALED state.  Fences must be reset before being submitted",
444483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                        reinterpret_cast<uint64_t &>(pFence->fence));
4445a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        }
44465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
444781c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes
444883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
444981c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes}
445081c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes
445151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic void PostCallRecordQueueSubmit(layer_data *dev_data, VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits,
445251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                                      VkFence fence) {
44539a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pQueue = GetQueueState(dev_data, queue);
44549a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pFence = GetFenceNode(dev_data, fence);
4455d7d60cccc862fee2d0b3ad410c5fdcc40ddc83aeChris Forbes
4456651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    // Mark the fence in-use.
4457651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    if (pFence) {
44589867daedbf52debc77d6568162ee21e071699b80Chris Forbes        SubmitFence(pQueue, pFence, std::max(1u, submitCount));
4459651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    }
4460651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
446151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    // Now process each individual submit
44625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
446351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        std::vector<VkCommandBuffer> cbs;
44645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubmitInfo *submit = &pSubmits[submit_idx];
44659867daedbf52debc77d6568162ee21e071699b80Chris Forbes        vector<SEMAPHORE_WAIT> semaphore_waits;
44669867daedbf52debc77d6568162ee21e071699b80Chris Forbes        vector<VkSemaphore> semaphore_signals;
44675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < submit->waitSemaphoreCount; ++i) {
446851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            VkSemaphore semaphore = submit->pWaitSemaphores[i];
446951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
447051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            if (pSemaphore) {
447151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                if (pSemaphore->signaler.first != VK_NULL_HANDLE) {
447251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    semaphore_waits.push_back({semaphore, pSemaphore->signaler.first, pSemaphore->signaler.second});
447351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    pSemaphore->in_use.fetch_add(1);
447451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                }
447551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->signaler.first = VK_NULL_HANDLE;
447651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->signaled = false;
447751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            }
447851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        }
447951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        for (uint32_t i = 0; i < submit->signalSemaphoreCount; ++i) {
448051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            VkSemaphore semaphore = submit->pSignalSemaphores[i];
448151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
448251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            if (pSemaphore) {
448351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->signaler.first = queue;
448451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->signaler.second = pQueue->seq + pQueue->submissions.size() + 1;
448551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->signaled = true;
448651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->in_use.fetch_add(1);
448751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                semaphore_signals.push_back(semaphore);
448851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            }
448951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        }
449051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        for (uint32_t i = 0; i < submit->commandBufferCount; i++) {
449151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            auto cb_node = GetCBNode(dev_data, submit->pCommandBuffers[i]);
449251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            if (cb_node) {
449351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                cbs.push_back(submit->pCommandBuffers[i]);
449451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                for (auto secondaryCmdBuffer : cb_node->secondaryCommandBuffers) {
449551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    cbs.push_back(secondaryCmdBuffer);
449651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                }
449751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                UpdateCmdBufImageLayouts(dev_data, cb_node);
449851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                incrementResources(dev_data, cb_node);
449951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                if (!cb_node->secondaryCommandBuffers.empty()) {
450051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    for (auto secondaryCmdBuffer : cb_node->secondaryCommandBuffers) {
450151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                        GLOBAL_CB_NODE *pSubCB = GetCBNode(dev_data, secondaryCmdBuffer);
450251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                        incrementResources(dev_data, pSubCB);
450351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    }
450451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                }
450551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            }
450651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        }
450751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        pQueue->submissions.emplace_back(cbs, semaphore_waits, semaphore_signals,
450851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                                         submit_idx == submitCount - 1 ? fence : VK_NULL_HANDLE);
450951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    }
451051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
451151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    if (pFence && !submitCount) {
451251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        // If no submissions, but just dropping a fence on the end of the queue,
451351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        // record an empty submission with just the fence, so we can determine
451451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        // its completion.
451551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        pQueue->submissions.emplace_back(std::vector<VkCommandBuffer>(), std::vector<SEMAPHORE_WAIT>(), std::vector<VkSemaphore>(),
451651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                                         fence);
451751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    }
451851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour}
451951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
452051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic bool PreCallValidateQueueSubmit(layer_data *dev_data, VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits,
452151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                                       VkFence fence) {
452251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    auto pFence = GetFenceNode(dev_data, fence);
452351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    bool skip_call = ValidateFenceForSubmit(dev_data, pFence);
452451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    if (skip_call) {
452551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        return true;
452651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    }
452751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
452851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    unordered_set<VkSemaphore> signaled_semaphores;
452951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    unordered_set<VkSemaphore> unsignaled_semaphores;
453051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    vector<VkCommandBuffer> current_cmds;
453151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> localImageLayoutMap = dev_data->imageLayoutMap;
453251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    // Now verify each individual submit
453351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
453451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        const VkSubmitInfo *submit = &pSubmits[submit_idx];
453551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        for (uint32_t i = 0; i < submit->waitSemaphoreCount; ++i) {
4536208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis            skip_call |= ValidateStageMaskGsTsEnables(dev_data, submit->pWaitDstStageMask[i], "vkQueueSubmit()",
4537208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                                                      VALIDATION_ERROR_00142, VALIDATION_ERROR_00143);
453801a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            VkSemaphore semaphore = submit->pWaitSemaphores[i];
45399a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
454001a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            if (pSemaphore) {
454151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                if (unsignaled_semaphores.count(semaphore) ||
4542440bdd357701497c3442e3515f12ac1cfffc180aTony Barbour                    (!(signaled_semaphores.count(semaphore)) && !(pSemaphore->signaled))) {
454383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |=
45441344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
45451344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                                reinterpret_cast<const uint64_t &>(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
4546226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                "Queue 0x%p is waiting on semaphore 0x%" PRIx64 " that has no way to be signaled.", queue,
4547226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                reinterpret_cast<const uint64_t &>(semaphore));
454851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                } else {
454951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    signaled_semaphores.erase(semaphore);
455051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    unsignaled_semaphores.insert(semaphore);
45511344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                }
45525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
45535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
45545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < submit->signalSemaphoreCount; ++i) {
455501a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            VkSemaphore semaphore = submit->pSignalSemaphores[i];
45569a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
455701a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            if (pSemaphore) {
4558440bdd357701497c3442e3515f12ac1cfffc180aTony Barbour                if (signaled_semaphores.count(semaphore) || (!(unsignaled_semaphores.count(semaphore)) && pSemaphore->signaled)) {
455983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |=
45601344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
45611344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                                reinterpret_cast<const uint64_t &>(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
4562226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                "Queue 0x%p is signaling semaphore 0x%" PRIx64
4563414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                                " that has already been signaled but not waited on by queue 0x%" PRIx64 ".",
4564226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                queue, reinterpret_cast<const uint64_t &>(semaphore),
45659867daedbf52debc77d6568162ee21e071699b80Chris Forbes                                reinterpret_cast<uint64_t &>(pSemaphore->signaler.first));
45661344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                } else {
456751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    unsignaled_semaphores.erase(semaphore);
456851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    signaled_semaphores.insert(semaphore);
45691344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                }
45700a32ed7bdf03e7bda914e03c0bfa6ebf400cdf5bMichael Lentine            }
45715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
45725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < submit->commandBufferCount; i++) {
45739a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto cb_node = GetCBNode(dev_data, submit->pCommandBuffers[i]);
457451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            skip_call |= ValidateCmdBufImageLayouts(dev_data, cb_node, localImageLayoutMap);
4575d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis            if (cb_node) {
457651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                current_cmds.push_back(submit->pCommandBuffers[i]);
457751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                skip_call |= validatePrimaryCommandBufferState(
457851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    dev_data, cb_node, (int)std::count(current_cmds.begin(), current_cmds.end(), submit->pCommandBuffers[i]));
4579d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                skip_call |= validateQueueFamilyIndices(dev_data, cb_node, queue);
458051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
4581ea371fa7c8c57edb4d1436e4570cf54f3fc0463fTobin Ehlis                // Potential early exit here as bad object state may crash in delayed function calls
458251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                if (skip_call) {
458351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    return true;
458451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                }
458551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
45861344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                // Call submit-time functions to validate/update state
4587d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                for (auto &function : cb_node->validate_functions) {
458883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |= function();
45891344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                }
4590d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                for (auto &function : cb_node->eventUpdates) {
459183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |= function(queue);
45921344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                }
4593d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                for (auto &function : cb_node->queryUpdates) {
459483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |= function(queue);
4595d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                }
45961344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis            }
45975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
45989867daedbf52debc77d6568162ee21e071699b80Chris Forbes    }
459951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    return skip_call;
460051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour}
46019867daedbf52debc77d6568162ee21e071699b80Chris Forbes
460251920949f887ce8d3666c73c28ff19a5d8325a37Tony BarbourVKAPI_ATTR VkResult VKAPI_CALL QueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence) {
460351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
460451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    std::unique_lock<std::mutex> lock(global_lock);
460551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
460651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    bool skip = PreCallValidateQueueSubmit(dev_data, queue, submitCount, pSubmits, fence);
4607b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
46085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4609440bdd357701497c3442e3515f12ac1cfffc180aTony Barbour    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
461051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
461151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    VkResult result = dev_data->dispatch_table.QueueSubmit(queue, submitCount, pSubmits, fence);
461251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
461351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    lock.lock();
461451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    PostCallRecordQueueSubmit(dev_data, queue, submitCount, pSubmits, fence);
461551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    lock.unlock();
46165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
46175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
46185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4619f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultzstatic bool PreCallValidateAllocateMemory(layer_data *dev_data) {
4620f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    bool skip = false;
4621f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    if (dev_data->memObjMap.size() >= dev_data->phys_dev_properties.properties.limits.maxMemoryAllocationCount) {
4622f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
4623f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz                        reinterpret_cast<const uint64_t &>(dev_data->device), __LINE__, VALIDATION_ERROR_00611, "MEM",
4624f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz                        "Number of currently valid memory objects is not less than the maximum allowed (%u). %s",
4625f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz                        dev_data->phys_dev_properties.properties.limits.maxMemoryAllocationCount,
4626f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz                        validation_error_map[VALIDATION_ERROR_00611]);
4627f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    }
4628f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    return skip;
4629f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz}
4630f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz
4631f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultzstatic void PostCallRecordAllocateMemory(layer_data *dev_data, const VkMemoryAllocateInfo *pAllocateInfo, VkDeviceMemory *pMemory) {
4632f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    add_mem_obj_info(dev_data, dev_data->device, *pMemory, pAllocateInfo);
4633f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    return;
4634f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz}
4635f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz
463689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL AllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo,
463789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                              const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory) {
4638f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
463956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
4640f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    std::unique_lock<std::mutex> lock(global_lock);
4641f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    bool skip = PreCallValidateAllocateMemory(dev_data);
4642f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    if (!skip) {
4643f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        lock.unlock();
4644f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        result = dev_data->dispatch_table.AllocateMemory(device, pAllocateInfo, pAllocator, pMemory);
4645f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        lock.lock();
4646f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        if (VK_SUCCESS == result) {
4647f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz            PostCallRecordAllocateMemory(dev_data, pAllocateInfo, pMemory);
4648f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        }
4649e12739a56d02ca2fb5f0273862668e7475a21a6cMark Lobodzinski    }
46505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
46515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
46525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4653177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis// For given obj node, if it is use, flag a validation error and return callback result, else return false
4654177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlisbool ValidateObjectNotInUse(const layer_data *dev_data, BASE_NODE *obj_node, VK_OBJECT obj_struct,
4655177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis                            UNIQUE_VALIDATION_ERROR_CODE error_code) {
4656cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.object_in_use) return false;
4657177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    bool skip = false;
4658177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    if (obj_node->in_use.load()) {
4659177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, obj_struct.type, obj_struct.handle, __LINE__,
4660177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis                        error_code, "DS", "Cannot delete %s 0x%" PRIx64 " that is currently in use by a command buffer. %s",
4661177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis                        object_type_to_string(obj_struct.type), obj_struct.handle, validation_error_map[error_code]);
4662177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    }
4663177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    return skip;
4664177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis}
46655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4666177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlisstatic bool PreCallValidateFreeMemory(layer_data *dev_data, VkDeviceMemory mem, DEVICE_MEM_INFO **mem_info, VK_OBJECT *obj_struct) {
46679a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *mem_info = GetMemObjInfo(dev_data, mem);
466894165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(mem), VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT};
4669cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.free_memory) return false;
4670177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    bool skip = false;
4671177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    if (*mem_info) {
4672177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *mem_info, *obj_struct, VALIDATION_ERROR_00620);
4673177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    }
4674177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    return skip;
4675177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis}
46765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4677177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlisstatic void PostCallRecordFreeMemory(layer_data *dev_data, VkDeviceMemory mem, DEVICE_MEM_INFO *mem_info, VK_OBJECT obj_struct) {
4678177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    // Clear mem binding for any bound objects
467947705d01140c9f1492885e6efc5fa262e7e1c6a0Tobin Ehlis    for (auto obj : mem_info->obj_bindings) {
468047705d01140c9f1492885e6efc5fa262e7e1c6a0Tobin Ehlis        log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, obj.type, obj.handle, __LINE__, MEMTRACK_FREED_MEM_REF,
468147705d01140c9f1492885e6efc5fa262e7e1c6a0Tobin Ehlis                "MEM", "VK Object 0x%" PRIxLEAST64 " still has a reference to mem obj 0x%" PRIxLEAST64, obj.handle,
468247705d01140c9f1492885e6efc5fa262e7e1c6a0Tobin Ehlis                (uint64_t)mem_info->mem);
468347705d01140c9f1492885e6efc5fa262e7e1c6a0Tobin Ehlis        switch (obj.type) {
4684cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT: {
46859a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto image_state = GetImageState(dev_data, reinterpret_cast<VkImage &>(obj.handle));
4686cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                assert(image_state);  // Any destroyed images should already be removed from bindings
4687cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                image_state->binding.mem = MEMORY_UNBOUND;
4688cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4689cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4690cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT: {
46919a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto buffer_state = GetBufferState(dev_data, reinterpret_cast<VkBuffer &>(obj.handle));
4692cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                assert(buffer_state);  // Any destroyed buffers should already be removed from bindings
4693cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                buffer_state->binding.mem = MEMORY_UNBOUND;
4694cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4695cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4696cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
4697cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // Should only have buffer or image objects bound to memory
4698cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                assert(0);
4699177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        }
4700177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    }
4701177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    // Any bound cmd buffers are now invalid
470239c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, mem_info->cb_bindings, obj_struct);
4703177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    dev_data->memObjMap.erase(mem);
4704177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis}
4705177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis
4706177063aac84fac6f4e650c2629a08b48be643f96Tobin EhlisVKAPI_ATTR void VKAPI_CALL FreeMemory(VkDevice device, VkDeviceMemory mem, const VkAllocationCallbacks *pAllocator) {
470756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
4708177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    DEVICE_MEM_INFO *mem_info = nullptr;
4709177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    VK_OBJECT obj_struct;
4710b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
4711177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    bool skip = PreCallValidateFreeMemory(dev_data, mem, &mem_info, &obj_struct);
4712177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    if (!skip) {
4713177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        lock.unlock();
4714177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        dev_data->dispatch_table.FreeMemory(device, mem, pAllocator);
4715177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        lock.lock();
4716405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (mem != VK_NULL_HANDLE) {
4717405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordFreeMemory(dev_data, mem, mem_info, obj_struct);
4718405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
471974243a735fe102b370237ddf80d3e6f7ec5246dbMark Mueller    }
47205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
47215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4722f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis// Validate that given Map memory range is valid. This means that the memory should not already be mapped,
4723f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis//  and that the size of the map range should be:
4724f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis//  1. Not zero
4725f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis//  2. Within the size of the memory allocation
472651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool ValidateMapMemRange(layer_data *dev_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size) {
472783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
47285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
47295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (size == 0) {
473051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        skip_call = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
473183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                            (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, "MEM",
473283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                            "VkMapMemory: Attempting to map memory range of size zero");
47335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
47345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
473551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto mem_element = dev_data->memObjMap.find(mem);
473651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (mem_element != dev_data->memObjMap.end()) {
473757fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        auto mem_info = mem_element->second.get();
47385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // It is an application error to call VkMapMemory on an object that is already mapped
4739de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        if (mem_info->mem_range.size != 0) {
474051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            skip_call = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
474183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, "MEM",
474283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                "VkMapMemory: Attempting to map memory on an already-mapped object 0x%" PRIxLEAST64, (uint64_t)mem);
47435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
47445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
47455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Validate that offset + size is within object's allocationSize
47465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (size == VK_WHOLE_SIZE) {
4747de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis            if (offset >= mem_info->alloc_info.allocationSize) {
474851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                skip_call =
474951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
475051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                            (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, "MEM",
475151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                            "Mapping Memory from 0x%" PRIx64 " to 0x%" PRIx64
475251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                            " with size of VK_WHOLE_SIZE oversteps total array size 0x%" PRIx64,
475351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                            offset, mem_info->alloc_info.allocationSize, mem_info->alloc_info.allocationSize);
47545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
47555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
4756de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis            if ((offset + size) > mem_info->alloc_info.allocationSize) {
4757f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                skip_call = log_msg(
475851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
4759f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    (uint64_t)mem, __LINE__, VALIDATION_ERROR_00628, "MEM",
4760f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    "Mapping Memory from 0x%" PRIx64 " to 0x%" PRIx64 " oversteps total array size 0x%" PRIx64 ". %s", offset,
4761f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    size + offset, mem_info->alloc_info.allocationSize, validation_error_map[VALIDATION_ERROR_00628]);
47625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
47635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
47645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
476583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
47665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
47675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
476851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void storeMemRanges(layer_data *dev_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size) {
47699a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto mem_info = GetMemObjInfo(dev_data, mem);
477057fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    if (mem_info) {
4771de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        mem_info->mem_range.offset = offset;
4772de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        mem_info->mem_range.size = size;
47735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
47745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
47755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
477651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool deleteMemRanges(layer_data *dev_data, VkDeviceMemory mem) {
477783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
47789a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto mem_info = GetMemObjInfo(dev_data, mem);
477957fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    if (mem_info) {
4780de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        if (!mem_info->mem_range.size) {
47815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Valid Usage: memory must currently be mapped
478251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            skip_call = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
4783f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                                (uint64_t)mem, __LINE__, VALIDATION_ERROR_00649, "MEM",
4784f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                                "Unmapping Memory without memory being mapped: mem obj 0x%" PRIxLEAST64 ". %s", (uint64_t)mem,
4785f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                                validation_error_map[VALIDATION_ERROR_00649]);
47865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
4787de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        mem_info->mem_range.size = 0;
47885f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski        if (mem_info->shadow_copy) {
47895f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            free(mem_info->shadow_copy_base);
47905f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_copy_base = 0;
47915f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_copy = 0;
47925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
47935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
479483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
47955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
47965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
47975f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski// Guard value for pad data
47985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic char NoncoherentMemoryFillValue = 0xb;
47995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
48005f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinskistatic void initializeAndTrackMemory(layer_data *dev_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size,
48015f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                     void **ppData) {
48029a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto mem_info = GetMemObjInfo(dev_data, mem);
480357fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    if (mem_info) {
4804de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        mem_info->p_driver_data = *ppData;
4805de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        uint32_t index = mem_info->alloc_info.memoryTypeIndex;
4806b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis        if (dev_data->phys_dev_mem_props.memoryTypes[index].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) {
48075f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_copy = 0;
48085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
48095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (size == VK_WHOLE_SIZE) {
48105f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                size = mem_info->alloc_info.allocationSize - offset;
48115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
48125f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_pad_size = dev_data->phys_dev_properties.properties.limits.minMemoryMapAlignment;
48135f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            assert(vk_safe_modulo(mem_info->shadow_pad_size,
48145f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                  dev_data->phys_dev_properties.properties.limits.minMemoryMapAlignment) == 0);
48155f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            // Ensure start of mapped region reflects hardware alignment constraints
48165f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            uint64_t map_alignment = dev_data->phys_dev_properties.properties.limits.minMemoryMapAlignment;
48175f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski
48185f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            // From spec: (ppData - offset) must be aligned to at least limits::minMemoryMapAlignment.
48195f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            uint64_t start_offset = offset % map_alignment;
48205f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            // Data passed to driver will be wrapped by a guardband of data to detect over- or under-writes.
4821bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            mem_info->shadow_copy_base =
4822bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                malloc(static_cast<size_t>(2 * mem_info->shadow_pad_size + size + map_alignment + start_offset));
48235f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski
48245f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_copy =
48255f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                reinterpret_cast<char *>((reinterpret_cast<uintptr_t>(mem_info->shadow_copy_base) + map_alignment) &
4826bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         ~(map_alignment - 1)) +
4827bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                start_offset;
48285f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            assert(vk_safe_modulo(reinterpret_cast<uintptr_t>(mem_info->shadow_copy) + mem_info->shadow_pad_size - start_offset,
48295f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                  map_alignment) == 0);
48305f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski
48316e17c244b21ce43ac57404a00a0d844039eed363Mark Lobodzinski            memset(mem_info->shadow_copy, NoncoherentMemoryFillValue, static_cast<size_t>(2 * mem_info->shadow_pad_size + size));
48325f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            *ppData = static_cast<char *>(mem_info->shadow_copy) + mem_info->shadow_pad_size;
48335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
48345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
48355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
48365f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski
4837a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis// Verify that state for fence being waited on is appropriate. That is,
48389867daedbf52debc77d6568162ee21e071699b80Chris Forbes//  a fence being waited on should not already be signaled and
4839a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis//  it should have been submitted on a queue or during acquire next image
484049f6132af865afd5b7f413c91125971ac97c135aChris Forbesstatic inline bool verifyWaitFenceState(layer_data *dev_data, VkFence fence, const char *apiCall) {
484183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
48429b48b44dd917f95b5f34dd629ec4076fc87eb3a2Chris Forbes
48439a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pFence = GetFenceNode(dev_data, fence);
48449b48b44dd917f95b5f34dd629ec4076fc87eb3a2Chris Forbes    if (pFence) {
4845cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes        if (pFence->state == FENCE_UNSIGNALED) {
484683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
484783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 reinterpret_cast<uint64_t &>(fence), __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM",
4848cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "%s called for fence 0x%" PRIxLEAST64
4849cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 " which has not been submitted on a Queue or during "
485083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 "acquire next image.",
485183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 apiCall, reinterpret_cast<uint64_t &>(fence));
48525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
48535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
485483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
48555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
4856a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis
4857b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlisstatic void RetireFence(layer_data *dev_data, VkFence fence) {
48589a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pFence = GetFenceNode(dev_data, fence);
4859b3ecd4c1fb44a2e65dfc13256afa9150aabde1d4Chris Forbes    if (pFence->signaler.first != VK_NULL_HANDLE) {
486025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Fence signaller is a queue -- use this as proof that prior operations on that queue have completed.
48619a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        RetireWorkOnQueue(dev_data, GetQueueState(dev_data, pFence->signaler.first), pFence->signaler.second);
4862bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    } else {
486325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Fence signaller is the WSI. We're not tracking what the WSI op actually /was/ in CV yet, but we need to mark
486425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // the fence as retired.
4865d4513979120463171eb479cdded9336eb9944da1Chris Forbes        pFence->state = FENCE_RETIRED;
4866d4513979120463171eb479cdded9336eb9944da1Chris Forbes    }
4867b3ecd4c1fb44a2e65dfc13256afa9150aabde1d4Chris Forbes}
4868b3ecd4c1fb44a2e65dfc13256afa9150aabde1d4Chris Forbes
4869accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlisstatic bool PreCallValidateWaitForFences(layer_data *dev_data, uint32_t fence_count, const VkFence *fences) {
4870cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.wait_for_fences) return false;
4871accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    bool skip = false;
4872accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    for (uint32_t i = 0; i < fence_count; i++) {
4873accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis        skip |= verifyWaitFenceState(dev_data, fences[i], "vkWaitForFences");
4874b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis        skip |= VerifyQueueStateToFence(dev_data, fences[i]);
4875accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    }
4876accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    return skip;
4877accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis}
4878accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis
4879b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlisstatic void PostCallRecordWaitForFences(layer_data *dev_data, uint32_t fence_count, const VkFence *fences, VkBool32 wait_all) {
4880b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    // When we know that all fences are complete we can clean/remove their CBs
4881accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    if ((VK_TRUE == wait_all) || (1 == fence_count)) {
4882accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis        for (uint32_t i = 0; i < fence_count; i++) {
4883b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis            RetireFence(dev_data, fences[i]);
4884accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis        }
4885accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    }
4886accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    // NOTE : Alternate case not handled here is when some fences have completed. In
4887accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    //  this case for app to guarantee which fences completed it will have to call
4888b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    //  vkGetFenceStatus() at which point we'll clean/remove their CBs if complete.
4889accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis}
4890accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis
4891bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL WaitForFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences, VkBool32 waitAll,
4892bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                             uint64_t timeout) {
489356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
48945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Verify fence status of submitted fences
4895b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
4896accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    bool skip = PreCallValidateWaitForFences(dev_data, fenceCount, pFences);
4897b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
4898cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
4899a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis
49004a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.WaitForFences(device, fenceCount, pFences, waitAll, timeout);
4901414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller
49025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
4903b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
4904b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis        PostCallRecordWaitForFences(dev_data, fenceCount, pFences, waitAll);
4905b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
49065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
49075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
49085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
49095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4910f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlisstatic bool PreCallValidateGetFenceStatus(layer_data *dev_data, VkFence fence) {
4911cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.get_fence_state) return false;
4912f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis    return verifyWaitFenceState(dev_data, fence, "vkGetFenceStatus");
4913f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis}
4914f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis
4915b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlisstatic void PostCallRecordGetFenceStatus(layer_data *dev_data, VkFence fence) { RetireFence(dev_data, fence); }
4916f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis
491789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL GetFenceStatus(VkDevice device, VkFence fence) {
491856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
4919b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
4920f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis    bool skip = PreCallValidateGetFenceStatus(dev_data, fence);
4921b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
4922cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
4923a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis
49244a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.GetFenceStatus(device, fence);
49255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
4926f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis        lock.lock();
4927b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis        PostCallRecordGetFenceStatus(dev_data, fence);
4928f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis        lock.unlock();
49295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
49305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
49315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
49325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
49333b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlisstatic void PostCallRecordGetDeviceQueue(layer_data *dev_data, uint32_t q_family_index, VkQueue queue) {
49343b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    // Add queue to tracking set only if it is new
49353b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    auto result = dev_data->queues.emplace(queue);
49363b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    if (result.second == true) {
493736c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlis        QUEUE_STATE *queue_state = &dev_data->queueMap[queue];
49383b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis        queue_state->queue = queue;
49393b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis        queue_state->queueFamilyIndex = q_family_index;
49403b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis        queue_state->seq = 0;
49413b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    }
49423b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis}
49433b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis
4944bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL GetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue *pQueue) {
494556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
49464a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.GetDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue);
4947b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::lock_guard<std::mutex> lock(global_lock);
4948b376edacad6f7ab3fcc0a914e9b1673a9fcd5143Mark Lobodzinski
49493b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    PostCallRecordGetDeviceQueue(dev_data, queueFamilyIndex, *pQueue);
49505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
49515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
495236c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic bool PreCallValidateQueueWaitIdle(layer_data *dev_data, VkQueue queue, QUEUE_STATE **queue_state) {
49539a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *queue_state = GetQueueState(dev_data, queue);
4954cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.queue_wait_idle) return false;
4955e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis    return VerifyQueueStateToSeq(dev_data, *queue_state, (*queue_state)->seq + (*queue_state)->submissions.size());
49564273a1c157585a645dca4c960086032793899d05Tobin Ehlis}
49574273a1c157585a645dca4c960086032793899d05Tobin Ehlis
495836c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic void PostCallRecordQueueWaitIdle(layer_data *dev_data, QUEUE_STATE *queue_state) {
4959e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis    RetireWorkOnQueue(dev_data, queue_state, queue_state->seq + queue_state->submissions.size());
49604273a1c157585a645dca4c960086032793899d05Tobin Ehlis}
49614273a1c157585a645dca4c960086032793899d05Tobin Ehlis
496289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL QueueWaitIdle(VkQueue queue) {
496356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
496436c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlis    QUEUE_STATE *queue_state = nullptr;
49659867daedbf52debc77d6568162ee21e071699b80Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
49664273a1c157585a645dca4c960086032793899d05Tobin Ehlis    bool skip = PreCallValidateQueueWaitIdle(dev_data, queue, &queue_state);
49679867daedbf52debc77d6568162ee21e071699b80Chris Forbes    lock.unlock();
4968cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
49694a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.QueueWaitIdle(queue);
49704273a1c157585a645dca4c960086032793899d05Tobin Ehlis    if (VK_SUCCESS == result) {
4971e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis        lock.lock();
4972e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis        PostCallRecordQueueWaitIdle(dev_data, queue_state);
4973e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis        lock.unlock();
49744273a1c157585a645dca4c960086032793899d05Tobin Ehlis    }
49755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
49765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
49775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
49788767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlisstatic bool PreCallValidateDeviceWaitIdle(layer_data *dev_data) {
4979cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.device_wait_idle) return false;
49808767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    bool skip = false;
49818767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    for (auto &queue : dev_data->queueMap) {
49828767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        skip |= VerifyQueueStateToSeq(dev_data, &queue.second, queue.second.seq + queue.second.submissions.size());
49838767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    }
49848767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    return skip;
49858767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis}
49868767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis
49878767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlisstatic void PostCallRecordDeviceWaitIdle(layer_data *dev_data) {
49888767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    for (auto &queue : dev_data->queueMap) {
49898767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        RetireWorkOnQueue(dev_data, &queue.second, queue.second.seq + queue.second.submissions.size());
49908767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    }
49918767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis}
49928767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis
499389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL DeviceWaitIdle(VkDevice device) {
499456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
4995b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
49968767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    bool skip = PreCallValidateDeviceWaitIdle(dev_data);
4997b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
4998cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
49994a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.DeviceWaitIdle(device);
50008767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    if (VK_SUCCESS == result) {
50018767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        lock.lock();
50028767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        PostCallRecordDeviceWaitIdle(dev_data);
50038767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        lock.unlock();
50048767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    }
50055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
50065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
50075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
50081d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlisstatic bool PreCallValidateDestroyFence(layer_data *dev_data, VkFence fence, FENCE_NODE **fence_node, VK_OBJECT *obj_struct) {
50099a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *fence_node = GetFenceNode(dev_data, fence);
50101d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(fence), VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT};
5011cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_fence) return false;
50121d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    bool skip = false;
50131d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    if (*fence_node) {
50141d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        if ((*fence_node)->state == FENCE_INFLIGHT) {
50151d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
5016208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                            (uint64_t)(fence), __LINE__, VALIDATION_ERROR_00173, "DS", "Fence 0x%" PRIx64 " is in use. %s",
5017208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                            (uint64_t)(fence), validation_error_map[VALIDATION_ERROR_00173]);
50181d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        }
50191d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    }
50201d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    return skip;
50211d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis}
50221d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis
50231d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlisstatic void PostCallRecordDestroyFence(layer_data *dev_data, VkFence fence) { dev_data->fenceMap.erase(fence); }
50241d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis
502589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL DestroyFence(VkDevice device, VkFence fence, const VkAllocationCallbacks *pAllocator) {
502656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
50271d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    // Common data objects used pre & post call
50281d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    FENCE_NODE *fence_node = nullptr;
50291d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    VK_OBJECT obj_struct;
5030b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
50311d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    bool skip = PreCallValidateDestroyFence(dev_data, fence, &fence_node, &obj_struct);
50321344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
50331d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    if (!skip) {
50341d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        lock.unlock();
50354a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyFence(device, fence, pAllocator);
50361d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        lock.lock();
50371d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        PostCallRecordDestroyFence(dev_data, fence);
50381d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    }
50395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
50405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5041c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlisstatic bool PreCallValidateDestroySemaphore(layer_data *dev_data, VkSemaphore semaphore, SEMAPHORE_NODE **sema_node,
5042c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis                                            VK_OBJECT *obj_struct) {
50439a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *sema_node = GetSemaphoreNode(dev_data, semaphore);
5044c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(semaphore), VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT};
5045cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_semaphore) return false;
5046c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    bool skip = false;
5047c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    if (*sema_node) {
5048c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *sema_node, *obj_struct, VALIDATION_ERROR_00199);
5049c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    }
5050c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    return skip;
5051c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis}
5052c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis
5053c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlisstatic void PostCallRecordDestroySemaphore(layer_data *dev_data, VkSemaphore sema) { dev_data->semaphoreMap.erase(sema); }
5054c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis
5055bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroySemaphore(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks *pAllocator) {
505656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5057c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    SEMAPHORE_NODE *sema_node;
5058c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    VK_OBJECT obj_struct;
5059e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
5060c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    bool skip = PreCallValidateDestroySemaphore(dev_data, semaphore, &sema_node, &obj_struct);
5061eafbf0b68ee6ea6e0bf33f07e0058d00a96efd9aTobin Ehlis    if (!skip) {
5062eafbf0b68ee6ea6e0bf33f07e0058d00a96efd9aTobin Ehlis        lock.unlock();
50634a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroySemaphore(device, semaphore, pAllocator);
5064c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis        lock.lock();
5065c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis        PostCallRecordDestroySemaphore(dev_data, semaphore);
506699d938c90c2f000ee73fb13513dacf84ffa5651fMark Mueller    }
50675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
50685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
50694710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlisstatic bool PreCallValidateDestroyEvent(layer_data *dev_data, VkEvent event, EVENT_STATE **event_state, VK_OBJECT *obj_struct) {
50709a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *event_state = GetEventNode(dev_data, event);
507194165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(event), VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT};
5072cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_event) return false;
5073d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    bool skip = false;
5074d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    if (*event_state) {
5075d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *event_state, *obj_struct, VALIDATION_ERROR_00213);
5076d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    }
5077d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    return skip;
5078d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis}
5079d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis
50804710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlisstatic void PostCallRecordDestroyEvent(layer_data *dev_data, VkEvent event, EVENT_STATE *event_state, VK_OBJECT obj_struct) {
508139c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, event_state->cb_bindings, obj_struct);
5082d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    dev_data->eventMap.erase(event);
5083d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis}
5084d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis
508589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL DestroyEvent(VkDevice device, VkEvent event, const VkAllocationCallbacks *pAllocator) {
508656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
50874710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis    EVENT_STATE *event_state = nullptr;
5088d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    VK_OBJECT obj_struct;
5089b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5090d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    bool skip = PreCallValidateDestroyEvent(dev_data, event, &event_state, &obj_struct);
5091f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    if (!skip) {
5092f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis        lock.unlock();
50934a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyEvent(device, event, pAllocator);
5094d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis        lock.lock();
5095405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (event != VK_NULL_HANDLE) {
5096405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyEvent(dev_data, event, event_state, obj_struct);
5097405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
5098f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    }
50995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
51005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
510183c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlisstatic bool PreCallValidateDestroyQueryPool(layer_data *dev_data, VkQueryPool query_pool, QUERY_POOL_NODE **qp_state,
510283c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis                                            VK_OBJECT *obj_struct) {
51039a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *qp_state = GetQueryPoolNode(dev_data, query_pool);
510483c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(query_pool), VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT};
5105cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_query_pool) return false;
510683c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    bool skip = false;
510783c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    if (*qp_state) {
510883c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *qp_state, *obj_struct, VALIDATION_ERROR_01012);
510983c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    }
511083c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    return skip;
511183c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis}
511283c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis
5113bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic void PostCallRecordDestroyQueryPool(layer_data *dev_data, VkQueryPool query_pool, QUERY_POOL_NODE *qp_state,
5114bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           VK_OBJECT obj_struct) {
511583c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    invalidateCommandBuffers(dev_data, qp_state->cb_bindings, obj_struct);
511683c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    dev_data->queryPoolMap.erase(query_pool);
511783c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis}
511883c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis
5119bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks *pAllocator) {
512056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
512183c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    QUERY_POOL_NODE *qp_state = nullptr;
512283c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    VK_OBJECT obj_struct;
5123ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
512483c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    bool skip = PreCallValidateDestroyQueryPool(dev_data, queryPool, &qp_state, &obj_struct);
5125f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    if (!skip) {
5126f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis        lock.unlock();
51274a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyQueryPool(device, queryPool, pAllocator);
512883c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis        lock.lock();
5129405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (queryPool != VK_NULL_HANDLE) {
5130405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyQueryPool(dev_data, queryPool, qp_state, obj_struct);
5131405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
5132f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    }
51335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
51349fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlisstatic bool PreCallValidateGetQueryPoolResults(layer_data *dev_data, VkQueryPool query_pool, uint32_t first_query,
51359fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                               uint32_t query_count, VkQueryResultFlags flags,
51369fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                               unordered_map<QueryObject, vector<VkCommandBuffer>> *queries_in_flight) {
51379fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    for (auto cmd_buffer : dev_data->globalInFlightCmdBuffers) {
51389a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto cb = GetCBNode(dev_data, cmd_buffer);
51399fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        for (auto query_state_pair : cb->queryToStateMap) {
51409fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            (*queries_in_flight)[query_state_pair.first].push_back(cmd_buffer);
51415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
51425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5143cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.get_query_pool_results) return false;
51449fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    bool skip = false;
51459fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    for (uint32_t i = 0; i < query_count; ++i) {
51469fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        QueryObject query = {query_pool, first_query + i};
51479fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        auto qif_pair = queries_in_flight->find(query);
51489fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        auto query_state_pair = dev_data->queryToStateMap.find(query);
51499fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        if (query_state_pair != dev_data->queryToStateMap.end()) {
5150ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski            // Available and in flight
51519fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            if (qif_pair != queries_in_flight->end() && query_state_pair != dev_data->queryToStateMap.end() &&
51529fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                query_state_pair->second) {
51539fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                for (auto cmd_buffer : qif_pair->second) {
51549a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto cb = GetCBNode(dev_data, cmd_buffer);
51559fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    auto query_event_pair = cb->waitedEventsBeforeQueryReset.find(query);
51569fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    if (query_event_pair == cb->waitedEventsBeforeQueryReset.end()) {
51579fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
51589fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                        VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
51599fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                        "Cannot get query results on queryPool 0x%" PRIx64 " with index %d which is in flight.",
51609fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                        (uint64_t)(query_pool), first_query + i);
5161ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                    }
5162ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                }
5163ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                // Unavailable and in flight
51649fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            } else if (qif_pair != queries_in_flight->end() && query_state_pair != dev_data->queryToStateMap.end() &&
51659fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                       !query_state_pair->second) {
5166ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                // TODO : Can there be the same query in use by multiple command buffers in flight?
5167ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                bool make_available = false;
51689fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                for (auto cmd_buffer : qif_pair->second) {
51699a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto cb = GetCBNode(dev_data, cmd_buffer);
51709fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    make_available |= cb->queryToStateMap[query];
5171ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                }
5172ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                if (!(((flags & VK_QUERY_RESULT_PARTIAL_BIT) || (flags & VK_QUERY_RESULT_WAIT_BIT)) && make_available)) {
51739fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
51749fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                    VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
51759fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                    "Cannot get query results on queryPool 0x%" PRIx64 " with index %d which is unavailable.",
51769fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                    (uint64_t)(query_pool), first_query + i);
51775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
5178ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                // Unavailable
51799fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            } else if (query_state_pair != dev_data->queryToStateMap.end() && !query_state_pair->second) {
51809fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0,
51819fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
51829fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                "Cannot get query results on queryPool 0x%" PRIx64 " with index %d which is unavailable.",
51839fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                (uint64_t)(query_pool), first_query + i);
51849fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                // Uninitialized
51859fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            } else if (query_state_pair == dev_data->queryToStateMap.end()) {
51869fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0,
51879fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
51889fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                "Cannot get query results on queryPool 0x%" PRIx64
51899fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                " with index %d as data has not been collected for this index.",
51909fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                (uint64_t)(query_pool), first_query + i);
51915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
51925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
51935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
51949fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    return skip;
51959fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis}
51969fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis
51979fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlisstatic void PostCallRecordGetQueryPoolResults(layer_data *dev_data, VkQueryPool query_pool, uint32_t first_query,
51989fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                              uint32_t query_count,
51999fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                              unordered_map<QueryObject, vector<VkCommandBuffer>> *queries_in_flight) {
52009fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    for (uint32_t i = 0; i < query_count; ++i) {
52019fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        QueryObject query = {query_pool, first_query + i};
52029fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        auto qif_pair = queries_in_flight->find(query);
52039fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        auto query_state_pair = dev_data->queryToStateMap.find(query);
52049fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        if (query_state_pair != dev_data->queryToStateMap.end()) {
52059fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            // Available and in flight
52069fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            if (qif_pair != queries_in_flight->end() && query_state_pair != dev_data->queryToStateMap.end() &&
52079fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                query_state_pair->second) {
52089fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                for (auto cmd_buffer : qif_pair->second) {
52099a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto cb = GetCBNode(dev_data, cmd_buffer);
52109fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    auto query_event_pair = cb->waitedEventsBeforeQueryReset.find(query);
52119fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    if (query_event_pair != cb->waitedEventsBeforeQueryReset.end()) {
52129fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                        for (auto event : query_event_pair->second) {
52139fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                            dev_data->eventMap[event].needsSignaled = true;
52149fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                        }
52159fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    }
52169fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                }
52179fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            }
52189fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        }
52199fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    }
52209fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis}
52219fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis
52229fdee42cd357379efb9aa27f90beb75d1f824955Tobin EhlisVKAPI_ATTR VkResult VKAPI_CALL GetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount,
52239fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                                   size_t dataSize, void *pData, VkDeviceSize stride, VkQueryResultFlags flags) {
522456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
52259fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    unordered_map<QueryObject, vector<VkCommandBuffer>> queries_in_flight;
52269fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
52279fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    bool skip = PreCallValidateGetQueryPoolResults(dev_data, queryPool, firstQuery, queryCount, flags, &queries_in_flight);
5228b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
5229cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
52309fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    VkResult result =
52319fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        dev_data->dispatch_table.GetQueryPoolResults(device, queryPool, firstQuery, queryCount, dataSize, pData, stride, flags);
52329fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    lock.lock();
52339fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    PostCallRecordGetQueryPoolResults(dev_data, queryPool, firstQuery, queryCount, &queries_in_flight);
52349fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    lock.unlock();
52359fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    return result;
52365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
52375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5238825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Return true if given ranges intersect, else false
5239825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Prereq : For both ranges, range->end - range->start > 0. This case should have already resulted
5240825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  in an error so not checking that here
5241825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// pad_ranges bool indicates a linear and non-linear comparison which requires padding
5242825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// In the case where padding is required, if an alias is encountered then a validation error is reported and skip_call
5243825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  may be set by the callback function so caller should merge in skip_call value if padding case is possible.
52447dc3fbb89e2dcf3df8fc2e6639a867a959fef3f3Tobin Ehlisstatic bool rangesIntersect(layer_data const *dev_data, MEMORY_RANGE const *range1, MEMORY_RANGE const *range2, bool *skip_call) {
52457dc3fbb89e2dcf3df8fc2e6639a867a959fef3f3Tobin Ehlis    *skip_call = false;
5246825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto r1_start = range1->start;
5247825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto r1_end = range1->end;
5248825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto r2_start = range2->start;
5249825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto r2_end = range2->end;
5250825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    VkDeviceSize pad_align = 1;
5251825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    if (range1->linear != range2->linear) {
5252825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        pad_align = dev_data->phys_dev_properties.properties.limits.bufferImageGranularity;
5253825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    }
5254cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if ((r1_end & ~(pad_align - 1)) < (r2_start & ~(pad_align - 1))) return false;
5255cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if ((r1_start & ~(pad_align - 1)) > (r2_end & ~(pad_align - 1))) return false;
525647aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
5257825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    if (range1->linear != range2->linear) {
525853ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis        // In linear vs. non-linear case, warn of aliasing
5259825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        const char *r1_linear_str = range1->linear ? "Linear" : "Non-linear";
5260825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        const char *r1_type_str = range1->image ? "image" : "buffer";
5261825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        const char *r2_linear_str = range2->linear ? "linear" : "non-linear";
5262825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        const char *r2_type_str = range2->image ? "image" : "buffer";
5263825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        auto obj_type = range1->image ? VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT : VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT;
526453ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis        *skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, obj_type, range1->handle, 0,
526553ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis                              MEMTRACK_INVALID_ALIASING, "MEM", "%s %s 0x%" PRIx64 " is aliased with %s %s 0x%" PRIx64
526653ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis                                                                " which may indicate a bug. For further info refer to the "
526753ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis                                                                "Buffer-Image Granularity section of the Vulkan specification. "
526853ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis                                                                "(https://www.khronos.org/registry/vulkan/specs/1.0-extensions/"
526953ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis                                                                "xhtml/vkspec.html#resources-bufferimagegranularity)",
527053ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis                              r1_linear_str, r1_type_str, range1->handle, r2_linear_str, r2_type_str, range2->handle);
527147aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    }
5272825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    // Ranges intersect
5273825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    return true;
527447aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski}
5275623548a271287ae55415e45e3c654ee66d4e79ffTobin Ehlis// Simplified rangesIntersect that calls above function to check range1 for intersection with offset & end addresses
5276c3340a06ecac4d7b9540592cae339f8fc224d0b1Mark Lobodzinskibool rangesIntersect(layer_data const *dev_data, MEMORY_RANGE const *range1, VkDeviceSize offset, VkDeviceSize end) {
5277825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    // Create a local MEMORY_RANGE struct to wrap offset/size
5278825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    MEMORY_RANGE range_wrap;
5279825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    // Synch linear with range1 to avoid padding and potential validation error case
5280825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range_wrap.linear = range1->linear;
5281825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range_wrap.start = offset;
5282cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    range_wrap.end = end;
5283825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    bool tmp_bool;
52847dc3fbb89e2dcf3df8fc2e6639a867a959fef3f3Tobin Ehlis    return rangesIntersect(dev_data, range1, &range_wrap, &tmp_bool);
5285825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis}
5286cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis// For given mem_info, set all ranges valid that intersect [offset-end] range
5287cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis// TODO : For ranges where there is no alias, we may want to create new buffer ranges that are valid
5288cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlisstatic void SetMemRangesValid(layer_data const *dev_data, DEVICE_MEM_INFO *mem_info, VkDeviceSize offset, VkDeviceSize end) {
5289cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    bool tmp_bool = false;
5290f6e16b28b808a342cb92768001afa2cfeee08a11Tobin Ehlis    MEMORY_RANGE map_range = {};
5291cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    map_range.linear = true;
5292cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    map_range.start = offset;
5293cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    map_range.end = end;
5294cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    for (auto &handle_range_pair : mem_info->bound_ranges) {
52957dc3fbb89e2dcf3df8fc2e6639a867a959fef3f3Tobin Ehlis        if (rangesIntersect(dev_data, &handle_range_pair.second, &map_range, &tmp_bool)) {
5296cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis            // TODO : WARN here if tmp_bool true?
5297cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis            handle_range_pair.second.valid = true;
5298cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis        }
5299cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    }
5300cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis}
5301825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Object with given handle is being bound to memory w/ given mem_info struct.
5302825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  Track the newly bound memory range with given memoryOffset
5303825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  Also scan any previous ranges, track aliased ranges with new range, and flag an error if a linear
5304825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  and non-linear range incorrectly overlap.
5305825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Return true if an error is flagged and the user callback returns "true", otherwise false
5306825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// is_image indicates an image object, otherwise handle is for a buffer
5307825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// is_linear indicates a buffer or linear image
53087992c34b28dd617787f0e4d34fd023f894495edbCort Stratton// api_name API entry point that triggered this call
5309825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlisstatic bool InsertMemoryRange(layer_data const *dev_data, uint64_t handle, DEVICE_MEM_INFO *mem_info, VkDeviceSize memoryOffset,
53107992c34b28dd617787f0e4d34fd023f894495edbCort Stratton                              VkMemoryRequirements memRequirements, bool is_image, bool is_linear, const char *api_name) {
5311825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    bool skip_call = false;
53125360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    MEMORY_RANGE range;
5313825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
53147992c34b28dd617787f0e4d34fd023f894495edbCort Stratton    if (memoryOffset >= mem_info->alloc_info.allocationSize) {
53157992c34b28dd617787f0e4d34fd023f894495edbCort Stratton        UNIQUE_VALIDATION_ERROR_CODE error_code = is_image ? VALIDATION_ERROR_00805 : VALIDATION_ERROR_00793;
53167992c34b28dd617787f0e4d34fd023f894495edbCort Stratton        skip_call =
53177992c34b28dd617787f0e4d34fd023f894495edbCort Stratton            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
53187992c34b28dd617787f0e4d34fd023f894495edbCort Stratton                    reinterpret_cast<uint64_t &>(mem_info->mem), __LINE__, error_code, "MEM",
53197992c34b28dd617787f0e4d34fd023f894495edbCort Stratton                    "In %s, attempting to bind memory (0x%" PRIxLEAST64 ") to object (0x%" PRIxLEAST64
53207992c34b28dd617787f0e4d34fd023f894495edbCort Stratton                    "), memoryOffset=0x%" PRIxLEAST64 " must be less than the memory allocation size 0x%" PRIxLEAST64 ". %s",
53217992c34b28dd617787f0e4d34fd023f894495edbCort Stratton                    api_name, reinterpret_cast<uint64_t &>(mem_info->mem), handle, memoryOffset,
53227992c34b28dd617787f0e4d34fd023f894495edbCort Stratton                    mem_info->alloc_info.allocationSize, validation_error_map[error_code]);
53237992c34b28dd617787f0e4d34fd023f894495edbCort Stratton    }
53247992c34b28dd617787f0e4d34fd023f894495edbCort Stratton
5325825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range.image = is_image;
532647aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    range.handle = handle;
5327825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range.linear = is_linear;
5328f541bf53dee6daf82a4c8304354eac599a884d29Tobin Ehlis    range.valid = mem_info->global_valid;
5329825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range.memory = mem_info->mem;
533047aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    range.start = memoryOffset;
5331825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range.size = memRequirements.size;
533247aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    range.end = memoryOffset + memRequirements.size - 1;
53335360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    range.aliases.clear();
53345360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    // Update Memory aliasing
533575f4c8cec0996021a4258b9bf920a9e0fea4eac1Tobin 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
53365360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    // inserted into map before loop to get the final ptr, then we may enter loop when not needed & we check range against itself
53375360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    std::unordered_set<MEMORY_RANGE *> tmp_alias_ranges;
5338825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    for (auto &obj_range_pair : mem_info->bound_ranges) {
5339825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        auto check_range = &obj_range_pair.second;
53405360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis        bool intersection_error = false;
53417dc3fbb89e2dcf3df8fc2e6639a867a959fef3f3Tobin Ehlis        if (rangesIntersect(dev_data, &range, check_range, &intersection_error)) {
5342825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis            skip_call |= intersection_error;
5343825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis            range.aliases.insert(check_range);
53445360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis            tmp_alias_ranges.insert(check_range);
5345825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        }
5346825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    }
53475360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    mem_info->bound_ranges[handle] = std::move(range);
53485360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    for (auto tmp_range : tmp_alias_ranges) {
53495360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis        tmp_range->aliases.insert(&mem_info->bound_ranges[handle]);
53505360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    }
5351825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    if (is_image)
5352825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        mem_info->bound_images.insert(handle);
5353825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    else
5354825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        mem_info->bound_buffers.insert(handle);
5355825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
5356825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    return skip_call;
535747aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski}
535847aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
53599f12a235bb9c014878a98ce385b68587add2538aTobin Ehlisstatic bool InsertImageMemoryRange(layer_data const *dev_data, VkImage image, DEVICE_MEM_INFO *mem_info, VkDeviceSize mem_offset,
53607992c34b28dd617787f0e4d34fd023f894495edbCort Stratton                                   VkMemoryRequirements mem_reqs, bool is_linear, const char *api_name) {
53617992c34b28dd617787f0e4d34fd023f894495edbCort Stratton    return InsertMemoryRange(dev_data, reinterpret_cast<uint64_t &>(image), mem_info, mem_offset, mem_reqs, true, is_linear,
53627992c34b28dd617787f0e4d34fd023f894495edbCort Stratton                             api_name);
5363825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis}
5364825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
53659f12a235bb9c014878a98ce385b68587add2538aTobin Ehlisstatic bool InsertBufferMemoryRange(layer_data const *dev_data, VkBuffer buffer, DEVICE_MEM_INFO *mem_info, VkDeviceSize mem_offset,
53667992c34b28dd617787f0e4d34fd023f894495edbCort Stratton                                    VkMemoryRequirements mem_reqs, const char *api_name) {
53677992c34b28dd617787f0e4d34fd023f894495edbCort Stratton    return InsertMemoryRange(dev_data, reinterpret_cast<uint64_t &>(buffer), mem_info, mem_offset, mem_reqs, false, true, api_name);
5368825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis}
5369825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
5370825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Remove MEMORY_RANGE struct for give handle from bound_ranges of mem_info
5371825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  is_image indicates if handle is for image or buffer
5372825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  This function will also remove the handle-to-index mapping from the appropriate
5373825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  map and clean up any aliases for range being removed.
5374825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlisstatic void RemoveMemoryRange(uint64_t handle, DEVICE_MEM_INFO *mem_info, bool is_image) {
5375825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto erase_range = &mem_info->bound_ranges[handle];
5376825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    for (auto alias_range : erase_range->aliases) {
5377825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        alias_range->aliases.erase(erase_range);
537847aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    }
53795360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    erase_range->aliases.clear();
5380825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    mem_info->bound_ranges.erase(handle);
53811cba4e1b5940c6818572e05dcad5a3a47fafbc9eTobin Ehlis    if (is_image) {
5382825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        mem_info->bound_images.erase(handle);
53831cba4e1b5940c6818572e05dcad5a3a47fafbc9eTobin Ehlis    } else {
5384825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        mem_info->bound_buffers.erase(handle);
53851cba4e1b5940c6818572e05dcad5a3a47fafbc9eTobin Ehlis    }
538647aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski}
538747aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
5388842b2d28ded1c6e2c38491a81213d0e1d1b7295aMark Lobodzinskivoid RemoveBufferMemoryRange(uint64_t handle, DEVICE_MEM_INFO *mem_info) { RemoveMemoryRange(handle, mem_info, false); }
5389825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
53908c59133586421be878d393799b30044497f77727Mark Lobodzinskivoid RemoveImageMemoryRange(uint64_t handle, DEVICE_MEM_INFO *mem_info) { RemoveMemoryRange(handle, mem_info, true); }
5391825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
5392bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator) {
539356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5394e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    BUFFER_STATE *buffer_state = nullptr;
5395e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    VK_OBJECT obj_struct;
5396b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5397e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    bool skip = PreCallValidateDestroyBuffer(dev_data, buffer, &buffer_state, &obj_struct);
5398e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    if (!skip) {
5399b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
54004a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyBuffer(device, buffer, pAllocator);
5401e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis        lock.lock();
5402405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (buffer != VK_NULL_HANDLE) {
5403405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyBuffer(dev_data, buffer, buffer_state, obj_struct);
5404405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
540547aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    }
54065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
54075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5408bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyBufferView(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks *pAllocator) {
540956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5410f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    // Common data objects used pre & post call
54118e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    BUFFER_VIEW_STATE *buffer_view_state = nullptr;
54128e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    VK_OBJECT obj_struct;
5413a123662876eebfa844faa65ae3f071d3d77618ebTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
54148e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    // Validate state before calling down chain, update common data if we'll be calling down chain
54158e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    bool skip = PreCallValidateDestroyBufferView(dev_data, bufferView, &buffer_view_state, &obj_struct);
541638e26abbaa884eb48bfec4ddb4e0ae2c90634e06Tobin Ehlis    if (!skip) {
541738e26abbaa884eb48bfec4ddb4e0ae2c90634e06Tobin Ehlis        lock.unlock();
54184a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyBufferView(device, bufferView, pAllocator);
54198e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis        lock.lock();
5420405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (bufferView != VK_NULL_HANDLE) {
5421405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyBufferView(dev_data, bufferView, buffer_view_state, obj_struct);
5422405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
54235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
54245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
54255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
54262a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin EhlisVKAPI_ATTR void VKAPI_CALL DestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) {
542756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
54281facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    IMAGE_STATE *image_state = nullptr;
54292a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    VK_OBJECT obj_struct;
54302a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
54312a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    bool skip = PreCallValidateDestroyImage(dev_data, image, &image_state, &obj_struct);
54322a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    if (!skip) {
5433f940225c9e5e3e14b3f5a32d3ea360b585614600Tobin Ehlis        lock.unlock();
54344a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyImage(device, image, pAllocator);
54352a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis        lock.lock();
5436405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (image != VK_NULL_HANDLE) {
5437405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyImage(dev_data, image, image_state, obj_struct);
5438405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
54395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
54405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
54415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
54424261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinskistatic bool ValidateMemoryTypes(const layer_data *dev_data, const DEVICE_MEM_INFO *mem_info, const uint32_t memory_type_bits,
5443f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                                const char *funcName, UNIQUE_VALIDATION_ERROR_CODE msgCode) {
54444261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinski    bool skip_call = false;
5445de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis    if (((1 << mem_info->alloc_info.memoryTypeIndex) & memory_type_bits) == 0) {
5446f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen        skip_call =
5447f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
5448f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    reinterpret_cast<const uint64_t &>(mem_info->mem), __LINE__, msgCode, "MT",
5449f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    "%s(): MemoryRequirements->memoryTypeBits (0x%X) for this object type are not compatible with the memory "
5450f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    "type (0x%X) of this memory object 0x%" PRIx64 ". %s",
5451f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    funcName, memory_type_bits, mem_info->alloc_info.memoryTypeIndex,
5452f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    reinterpret_cast<const uint64_t &>(mem_info->mem), validation_error_map[msgCode]);
54534261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinski    }
54544261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinski    return skip_call;
54554261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinski}
54564261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinski
54579207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Strattonstatic bool PreCallValidateBindBufferMemory(layer_data *dev_data, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
54589207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    bool skip = false;
5459b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
54609207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton
54619a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto buffer_state = GetBufferState(dev_data, buffer);
54625cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (buffer_state) {
54639207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        // Track objects tied to memory
54649207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        uint64_t buffer_handle = reinterpret_cast<uint64_t &>(buffer);
5465c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        skip = ValidateSetMemBinding(dev_data, mem, buffer_handle, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, "vkBindBufferMemory()");
54662eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        if (!buffer_state->memory_requirements_checked) {
54672eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            // There's not an explicit requirement in the spec to call vkGetBufferMemoryRequirements() prior to calling
54689207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton            // BindBufferMemory, but it's implied in that memory being bound must conform with VkMemoryRequirements from
54699207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton            // vkGetBufferMemoryRequirements()
54709207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
54719207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            buffer_handle, __LINE__, DRAWSTATE_INVALID_BUFFER, "DS",
54729207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            "vkBindBufferMemory(): Binding memory to buffer 0x%" PRIxLEAST64
54739207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            " but vkGetBufferMemoryRequirements() has not been called on that buffer.",
54749207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            buffer_handle);
54752eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            // Make the call for them so we can verify the state
54762eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            lock.unlock();
54779207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton            dev_data->dispatch_table.GetBufferMemoryRequirements(dev_data->device, buffer, &buffer_state->requirements);
54782eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            lock.lock();
54792eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        }
548047aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
548147aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski        // Track and validate bound memory range information
54829a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto mem_info = GetMemObjInfo(dev_data, mem);
548357fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        if (mem_info) {
54849207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton            skip |= InsertBufferMemoryRange(dev_data, buffer, mem_info, memoryOffset, buffer_state->requirements,
54859207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                                            "vkBindBufferMemory()");
54869207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton            skip |= ValidateMemoryTypes(dev_data, mem_info, buffer_state->requirements.memoryTypeBits, "vkBindBufferMemory()",
54879207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                                        VALIDATION_ERROR_00797);
548847aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski        }
548947aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
54902c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves        // Validate memory requirements alignment
54912eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        if (vk_safe_modulo(memoryOffset, buffer_state->requirements.alignment) != 0) {
54929207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
54939207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            0, __LINE__, VALIDATION_ERROR_02174, "DS",
54949207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            "vkBindBufferMemory(): memoryOffset is 0x%" PRIxLEAST64
54959207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            " but must be an integer multiple of the "
54969207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            "VkMemoryRequirements::alignment value 0x%" PRIxLEAST64
54979207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            ", returned from a call to vkGetBufferMemoryRequirements with buffer. %s",
54989207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            memoryOffset, buffer_state->requirements.alignment, validation_error_map[VALIDATION_ERROR_02174]);
54992c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves        }
5500ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller
55012c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves        // Validate device limits alignments
5502ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller        static const VkBufferUsageFlagBits usage_list[3] = {
5503ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller            static_cast<VkBufferUsageFlagBits>(VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT),
5504bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT};
5505bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        static const char *memory_type[3] = {"texel", "uniform", "storage"};
5506bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        static const char *offset_name[3] = {"minTexelBufferOffsetAlignment", "minUniformBufferOffsetAlignment",
5507bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                             "minStorageBufferOffsetAlignment"};
5508cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski
55099207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        // TODO:  vk_validation_stats.py cannot abide braces immediately preceding or following a validation error enum
5510cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        // clang-format off
55119207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    static const UNIQUE_VALIDATION_ERROR_CODE msgCode[3] = { VALIDATION_ERROR_00794, VALIDATION_ERROR_00795,
55129207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton      VALIDATION_ERROR_00796 };
5513cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        // clang-format on
5514ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller
5515ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller        // Keep this one fresh!
5516ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller        const VkDeviceSize offset_requirement[3] = {
5517ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller            dev_data->phys_dev_properties.properties.limits.minTexelBufferOffsetAlignment,
5518ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller            dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment,
5519bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            dev_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment};
55208718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis        VkBufferUsageFlags usage = dev_data->bufferMap[buffer].get()->createInfo.usage;
5521ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller
5522ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller        for (int i = 0; i < 3; i++) {
5523ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller            if (usage & usage_list[i]) {
5524ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller                if (vk_safe_modulo(memoryOffset, offset_requirement[i]) != 0) {
55259207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                    skip |= log_msg(
5526cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0,
5527cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        __LINE__, msgCode[i], "DS", "vkBindBufferMemory(): %s memoryOffset is 0x%" PRIxLEAST64
5528cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                    " but must be a multiple of "
5529cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                    "device limit %s 0x%" PRIxLEAST64 ". %s",
5530cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        memory_type[i], memoryOffset, offset_name[i], offset_requirement[i], validation_error_map[msgCode[i]]);
5531ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller                }
55322c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves            }
55332c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves        }
55345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
55359207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    return skip;
55369207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton}
55379207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton
55389207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Strattonstatic void PostCallRecordBindBufferMemory(layer_data *dev_data, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
55399207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    std::unique_lock<std::mutex> lock(global_lock);
55409207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    auto buffer_state = GetBufferState(dev_data, buffer);
55419207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    if (buffer_state) {
5542c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        // Track objects tied to memory
5543c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        uint64_t buffer_handle = reinterpret_cast<uint64_t &>(buffer);
5544c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        SetMemBinding(dev_data, mem, buffer_handle, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, "vkBindBufferMemory()");
5545c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton
55469207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        buffer_state->binding.mem = mem;
55479207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        buffer_state->binding.offset = memoryOffset;
55489207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        buffer_state->binding.size = buffer_state->requirements.size;
55499207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    }
55509207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton}
55519207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton
55529207132ef623d47fcbdfeb9ebc796eade35a2f4cCort StrattonVKAPI_ATTR VkResult VKAPI_CALL BindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
55539207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
55549207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
55559207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    bool skip = PreCallValidateBindBufferMemory(dev_data, buffer, mem, memoryOffset);
55569207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    if (!skip) {
55574a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.BindBufferMemory(device, buffer, mem, memoryOffset);
55589207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        if (result == VK_SUCCESS) {
55599207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton            PostCallRecordBindBufferMemory(dev_data, buffer, mem, memoryOffset);
55609207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        }
55615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
55625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
55635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
55645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5565bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL GetBufferMemoryRequirements(VkDevice device, VkBuffer buffer,
5566bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                       VkMemoryRequirements *pMemoryRequirements) {
556756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
556815caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    dev_data->dispatch_table.GetBufferMemoryRequirements(device, buffer, pMemoryRequirements);
55699a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto buffer_state = GetBufferState(dev_data, buffer);
557015caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    if (buffer_state) {
557115caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis        buffer_state->requirements = *pMemoryRequirements;
55722eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        buffer_state->memory_requirements_checked = true;
557315caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    }
55745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
55755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5576bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL GetImageMemoryRequirements(VkDevice device, VkImage image, VkMemoryRequirements *pMemoryRequirements) {
557756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
557815caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    dev_data->dispatch_table.GetImageMemoryRequirements(device, image, pMemoryRequirements);
55799a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto image_state = GetImageState(dev_data, image);
558015caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    if (image_state) {
558115caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis        image_state->requirements = *pMemoryRequirements;
55822eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        image_state->memory_requirements_checked = true;
558315caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    }
55845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
5585593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
5586bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyImageView(VkDevice device, VkImageView imageView, const VkAllocationCallbacks *pAllocator) {
558756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5588f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    // Common data objects used pre & post call
5589f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    IMAGE_VIEW_STATE *image_view_state = nullptr;
5590f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    VK_OBJECT obj_struct;
5591a123662876eebfa844faa65ae3f071d3d77618ebTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
5592f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    bool skip = PreCallValidateDestroyImageView(dev_data, imageView, &image_view_state, &obj_struct);
5593d85c42a6c1d6ad7a6f684c5bd793aab482b7705cTobin Ehlis    if (!skip) {
5594d85c42a6c1d6ad7a6f684c5bd793aab482b7705cTobin Ehlis        lock.unlock();
55954a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyImageView(device, imageView, pAllocator);
5596f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis        lock.lock();
5597405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (imageView != VK_NULL_HANDLE) {
5598405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyImageView(dev_data, imageView, image_view_state, obj_struct);
5599405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
5600d85c42a6c1d6ad7a6f684c5bd793aab482b7705cTobin Ehlis    }
56015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
56025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5603bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyShaderModule(VkDevice device, VkShaderModule shaderModule,
5604bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                               const VkAllocationCallbacks *pAllocator) {
560556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5606918c283ac4f8c604b79abd0c8b5706d2a7352a34Chris Forbes
5607b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
560851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    dev_data->shaderModuleMap.erase(shaderModule);
5609b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
5610918c283ac4f8c604b79abd0c8b5706d2a7352a34Chris Forbes
561151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    dev_data->dispatch_table.DestroyShaderModule(device, shaderModule, pAllocator);
56125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
56135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
56144c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic bool PreCallValidateDestroyPipeline(layer_data *dev_data, VkPipeline pipeline, PIPELINE_STATE **pipeline_state,
56158bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis                                           VK_OBJECT *obj_struct) {
561694165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *pipeline_state = getPipelineState(dev_data, pipeline);
561794165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(pipeline), VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT};
5618cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_pipeline) return false;
56198bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    bool skip = false;
56208bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    if (*pipeline_state) {
56211803032f91d772ff3589c9f5a51ade5b299ba538Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *pipeline_state, *obj_struct, VALIDATION_ERROR_00555);
56228bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    }
56238bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    return skip;
56248bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis}
56258bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis
56264c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic void PostCallRecordDestroyPipeline(layer_data *dev_data, VkPipeline pipeline, PIPELINE_STATE *pipeline_state,
56278bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis                                          VK_OBJECT obj_struct) {
56288bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    // Any bound cmd buffers are now invalid
562939c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, pipeline_state->cb_bindings, obj_struct);
56308bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    dev_data->pipelineMap.erase(pipeline);
56318bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis}
56328bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis
5633bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyPipeline(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks *pAllocator) {
563456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
56354c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    PIPELINE_STATE *pipeline_state = nullptr;
56368bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    VK_OBJECT obj_struct;
5637e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
56388bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    bool skip = PreCallValidateDestroyPipeline(dev_data, pipeline, &pipeline_state, &obj_struct);
5639f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    if (!skip) {
5640f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis        lock.unlock();
56414a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyPipeline(device, pipeline, pAllocator);
56428bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis        lock.lock();
5643405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (pipeline != VK_NULL_HANDLE) {
5644405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyPipeline(dev_data, pipeline, pipeline_state, obj_struct);
5645405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
5646f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    }
56475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
56485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5649bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyPipelineLayout(VkDevice device, VkPipelineLayout pipelineLayout,
5650bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkAllocationCallbacks *pAllocator) {
565156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5652e28cddb35c63274c13873b9a7060ad43b255c6f1Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
56536792ea7cc0ce5fa64b7bd6c946460608cbda91c7Tobin Ehlis    dev_data->pipelineLayoutMap.erase(pipelineLayout);
5654e28cddb35c63274c13873b9a7060ad43b255c6f1Tobin Ehlis    lock.unlock();
5655e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis
56564a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.DestroyPipelineLayout(device, pipelineLayout, pAllocator);
56575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
56585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5659d31a44af6da568692a73201825459689c9431867Tobin Ehlisstatic bool PreCallValidateDestroySampler(layer_data *dev_data, VkSampler sampler, SAMPLER_STATE **sampler_state,
5660806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis                                          VK_OBJECT *obj_struct) {
56619a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *sampler_state = GetSamplerState(dev_data, sampler);
566294165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(sampler), VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT};
5663cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_sampler) return false;
5664806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    bool skip = false;
5665806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    if (*sampler_state) {
5666806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *sampler_state, *obj_struct, VALIDATION_ERROR_00837);
5667806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    }
5668806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    return skip;
5669806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis}
5670806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis
5671d31a44af6da568692a73201825459689c9431867Tobin Ehlisstatic void PostCallRecordDestroySampler(layer_data *dev_data, VkSampler sampler, SAMPLER_STATE *sampler_state,
5672806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis                                         VK_OBJECT obj_struct) {
5673806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    // Any bound cmd buffers are now invalid
5674cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (sampler_state) invalidateCommandBuffers(dev_data, sampler_state->cb_bindings, obj_struct);
5675806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    dev_data->samplerMap.erase(sampler);
5676806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis}
5677806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis
5678bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroySampler(VkDevice device, VkSampler sampler, const VkAllocationCallbacks *pAllocator) {
567956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5680d31a44af6da568692a73201825459689c9431867Tobin Ehlis    SAMPLER_STATE *sampler_state = nullptr;
5681806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    VK_OBJECT obj_struct;
568256f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
5683806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    bool skip = PreCallValidateDestroySampler(dev_data, sampler, &sampler_state, &obj_struct);
5684f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    if (!skip) {
5685f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis        lock.unlock();
56864a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroySampler(device, sampler, pAllocator);
5687806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis        lock.lock();
5688405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (sampler != VK_NULL_HANDLE) {
5689405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroySampler(dev_data, sampler, sampler_state, obj_struct);
5690405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
5691f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    }
56925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
56935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
569479c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlisstatic void PostCallRecordDestroyDescriptorSetLayout(layer_data *dev_data, VkDescriptorSetLayout ds_layout) {
569579c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis    dev_data->descriptorSetLayoutMap.erase(ds_layout);
569679c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis}
569779c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis
5698bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyDescriptorSetLayout(VkDevice device, VkDescriptorSetLayout descriptorSetLayout,
5699bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      const VkAllocationCallbacks *pAllocator) {
570056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
570179c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis    dev_data->dispatch_table.DestroyDescriptorSetLayout(device, descriptorSetLayout, pAllocator);
570279c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
570379c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis    PostCallRecordDestroyDescriptorSetLayout(dev_data, descriptorSetLayout);
57045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
57055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5706c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlisstatic bool PreCallValidateDestroyDescriptorPool(layer_data *dev_data, VkDescriptorPool pool,
5707a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis                                                 DESCRIPTOR_POOL_STATE **desc_pool_state, VK_OBJECT *obj_struct) {
57089a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *desc_pool_state = GetDescriptorPoolState(dev_data, pool);
570994165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(pool), VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT};
5710cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_descriptor_pool) return false;
5711c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    bool skip = false;
5712c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    if (*desc_pool_state) {
57131803032f91d772ff3589c9f5a51ade5b299ba538Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *desc_pool_state, *obj_struct, VALIDATION_ERROR_00901);
5714c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    }
5715c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    return skip;
5716c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis}
5717c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis
5718c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlisstatic void PostCallRecordDestroyDescriptorPool(layer_data *dev_data, VkDescriptorPool descriptorPool,
5719a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis                                                DESCRIPTOR_POOL_STATE *desc_pool_state, VK_OBJECT obj_struct) {
5720c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    // Any bound cmd buffers are now invalid
572139c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, desc_pool_state->cb_bindings, obj_struct);
5722c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    // Free sets that were in this pool
5723c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    for (auto ds : desc_pool_state->sets) {
5724c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis        freeDescriptorSet(dev_data, ds);
5725c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    }
5726c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    dev_data->descriptorPoolMap.erase(descriptorPool);
5727c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis}
5728c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis
5729bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool,
5730bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkAllocationCallbacks *pAllocator) {
573156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5732a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis    DESCRIPTOR_POOL_STATE *desc_pool_state = nullptr;
5733c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    VK_OBJECT obj_struct;
5734c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
5735c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    bool skip = PreCallValidateDestroyDescriptorPool(dev_data, descriptorPool, &desc_pool_state, &obj_struct);
5736c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    if (!skip) {
5737c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis        lock.unlock();
5738c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis        dev_data->dispatch_table.DestroyDescriptorPool(device, descriptorPool, pAllocator);
5739c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis        lock.lock();
5740405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (descriptorPool != VK_NULL_HANDLE) {
5741405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyDescriptorPool(dev_data, descriptorPool, desc_pool_state, obj_struct);
5742405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
5743c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    }
57445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
5745bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis// Verify cmdBuffer in given cb_node is not in global in-flight set, and return skip_call result
5746bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis//  If this is a secondary command buffer, then make sure its primary is also in-flight
5747bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis//  If primary is not in-flight, then remove secondary from global in-flight set
5748bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis// This function is only valid at a point when cmdBuffer is being reset or freed
5749cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlisstatic bool checkCommandBufferInFlight(layer_data *dev_data, const GLOBAL_CB_NODE *cb_node, const char *action,
5750cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis                                       UNIQUE_VALIDATION_ERROR_CODE error_code) {
5751bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    bool skip_call = false;
5752bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    if (dev_data->globalInFlightCmdBuffers.count(cb_node->commandBuffer)) {
5753bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        // Primary CB or secondary where primary is also in-flight is an error
5754bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        if ((cb_node->createInfo.level != VK_COMMAND_BUFFER_LEVEL_SECONDARY) ||
5755bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis            (dev_data->globalInFlightCmdBuffers.count(cb_node->primaryCommandBuffer))) {
5756cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis            skip_call |=
5757cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
5758cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis                        reinterpret_cast<const uint64_t &>(cb_node->commandBuffer), __LINE__, error_code, "DS",
5759226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "Attempt to %s command buffer (0x%p) which is in use. %s", action, cb_node->commandBuffer,
5760226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        validation_error_map[error_code]);
5761bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        }
5762bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    }
5763bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    return skip_call;
5764bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis}
5765a964cad279f9749cd9ebfc7555247ff3bff26d53Chris Forbes
5766bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis// Iterate over all cmdBuffers in given commandPool and verify that each is not in use
5767cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlisstatic bool checkCommandBuffersInFlight(layer_data *dev_data, COMMAND_POOL_NODE *pPool, const char *action,
5768cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis                                        UNIQUE_VALIDATION_ERROR_CODE error_code) {
5769bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    bool skip_call = false;
5770a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes    for (auto cmd_buffer : pPool->commandBuffers) {
5771a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes        if (dev_data->globalInFlightCmdBuffers.count(cmd_buffer)) {
57729a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            skip_call |= checkCommandBufferInFlight(dev_data, GetCBNode(dev_data, cmd_buffer), action, error_code);
5773bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        }
5774bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    }
5775bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    return skip_call;
5776bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis}
57775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5778a01b5eb150981aad061238e64b173d0da8c11140Chris Forbesstatic void clearCommandBuffersInFlight(layer_data *dev_data, COMMAND_POOL_NODE *pPool) {
5779a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes    for (auto cmd_buffer : pPool->commandBuffers) {
5780a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes        dev_data->globalInFlightCmdBuffers.erase(cmd_buffer);
5781a964cad279f9749cd9ebfc7555247ff3bff26d53Chris Forbes    }
5782a964cad279f9749cd9ebfc7555247ff3bff26d53Chris Forbes}
5783a964cad279f9749cd9ebfc7555247ff3bff26d53Chris Forbes
5784bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL FreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount,
5785bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              const VkCommandBuffer *pCommandBuffers) {
578656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
57875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool skip_call = false;
5788b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5789c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes
57905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < commandBufferCount; i++) {
57919a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto cb_node = GetCBNode(dev_data, pCommandBuffers[i]);
57925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Delete CB information structure, and remove from commandBufferMap
57939f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        if (cb_node) {
5794cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis            skip_call |= checkCommandBufferInFlight(dev_data, cb_node, "free", VALIDATION_ERROR_00096);
5795c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes        }
5796c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes    }
5797c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes
5798cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return;
5799c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes
58009a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pPool = GetCommandPoolNode(dev_data, commandPool);
5801c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes    for (uint32_t i = 0; i < commandBufferCount; i++) {
58029a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto cb_node = GetCBNode(dev_data, pCommandBuffers[i]);
5803c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes        // Delete CB information structure, and remove from commandBufferMap
58049f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        if (cb_node) {
58059f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis            dev_data->globalInFlightCmdBuffers.erase(cb_node->commandBuffer);
58065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // reset prior to delete for data clean-up
58079f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis            resetCB(dev_data, cb_node->commandBuffer);
58089f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis            dev_data->commandBufferMap.erase(cb_node->commandBuffer);
58099f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis            delete cb_node;
58105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
58115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
58125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Remove commandBuffer reference from commandPoolMap
5813c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes        pPool->commandBuffers.remove(pCommandBuffers[i]);
58145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5815b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
5816e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis
58174a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.FreeCommandBuffers(device, commandPool, commandBufferCount, pCommandBuffers);
58185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
58195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
582089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo *pCreateInfo,
5821bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkAllocationCallbacks *pAllocator, VkCommandPool *pCommandPool) {
582256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
58235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
58244a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateCommandPool(device, pCreateInfo, pAllocator, pCommandPool);
58255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
58265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
5827b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
58285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->commandPoolMap[*pCommandPool].createFlags = pCreateInfo->flags;
58295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->commandPoolMap[*pCommandPool].queueFamilyIndex = pCreateInfo->queueFamilyIndex;
58305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
58315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
58325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
58335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
583489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo *pCreateInfo,
583589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                               const VkAllocationCallbacks *pAllocator, VkQueryPool *pQueryPool) {
583656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
58370c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    bool skip = false;
58380c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    if (pCreateInfo && pCreateInfo->queryType == VK_QUERY_TYPE_PIPELINE_STATISTICS) {
58390c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis        if (!dev_data->enabled_features.pipelineStatisticsQuery) {
58400c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0,
58410c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis                            __LINE__, VALIDATION_ERROR_01006, "DS",
58420c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis                            "Query pool with type VK_QUERY_TYPE_PIPELINE_STATISTICS created on a device "
58430c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis                            "with VkDeviceCreateInfo.pEnabledFeatures.pipelineStatisticsQuery == VK_FALSE. %s",
58440c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis                            validation_error_map[VALIDATION_ERROR_01006]);
58450c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis        }
58460c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    }
58470c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis
58480c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
58490c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    if (!skip) {
58500c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis        result = dev_data->dispatch_table.CreateQueryPool(device, pCreateInfo, pAllocator, pQueryPool);
58510c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    }
58525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
5853b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
5854eafbf0b68ee6ea6e0bf33f07e0058d00a96efd9aTobin Ehlis        QUERY_POOL_NODE *qp_node = &dev_data->queryPoolMap[*pQueryPool];
5855eafbf0b68ee6ea6e0bf33f07e0058d00a96efd9aTobin Ehlis        qp_node->createInfo = *pCreateInfo;
58565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
58575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
58585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
58595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
58605f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlisstatic bool PreCallValidateDestroyCommandPool(layer_data *dev_data, VkCommandPool pool, COMMAND_POOL_NODE **cp_state) {
58619a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *cp_state = GetCommandPoolNode(dev_data, pool);
5862cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_command_pool) return false;
58635f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    bool skip = false;
58645f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    if (*cp_state) {
58655f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        // Verify that command buffers in pool are complete (not in-flight)
58665f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        skip |= checkCommandBuffersInFlight(dev_data, *cp_state, "destroy command pool with", VALIDATION_ERROR_00077);
58675f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    }
58685f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    return skip;
58695f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis}
58705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
58715f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlisstatic void PostCallRecordDestroyCommandPool(layer_data *dev_data, VkCommandPool pool, COMMAND_POOL_NODE *cp_state) {
58729f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis    // Must remove cmdpool from cmdpoolmap, after removing all cmdbuffers in its list from the commandBufferMap
58735f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    clearCommandBuffersInFlight(dev_data, cp_state);
58745f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    for (auto cb : cp_state->commandBuffers) {
5875a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes        clear_cmd_buf_and_mem_references(dev_data, cb);
58769a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto cb_node = GetCBNode(dev_data, cb);
5877d61de0e68063faa169a9a632f811c9c9adec9897Tobin Ehlis        // Remove references to this cb_node prior to delete
5878d61de0e68063faa169a9a632f811c9c9adec9897Tobin Ehlis        // TODO : Need better solution here, resetCB?
58797165385f3a39f1f951f3a6a9a06ed2cce4642b6dMark Lobodzinski        for (auto obj : cb_node->object_bindings) {
58807165385f3a39f1f951f3a6a9a06ed2cce4642b6dMark Lobodzinski            removeCommandBufferBinding(dev_data, &obj, cb_node);
58817165385f3a39f1f951f3a6a9a06ed2cce4642b6dMark Lobodzinski        }
5882d61de0e68063faa169a9a632f811c9c9adec9897Tobin Ehlis        for (auto framebuffer : cb_node->framebuffers) {
58839a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto fb_state = GetFramebufferState(dev_data, framebuffer);
5884cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (fb_state) fb_state->cb_bindings.erase(cb_node);
5885d61de0e68063faa169a9a632f811c9c9adec9897Tobin Ehlis        }
5886cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        dev_data->commandBufferMap.erase(cb);  // Remove this command buffer
5887cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        delete cb_node;                        // delete CB info structure
5888a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes    }
58895f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    dev_data->commandPoolMap.erase(pool);
58905f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis}
5891e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis
58925f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis// Destroy commandPool along with all of the commandBuffers allocated from that pool
58935f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin EhlisVKAPI_ATTR void VKAPI_CALL DestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks *pAllocator) {
589456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
58955f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    COMMAND_POOL_NODE *cp_state = nullptr;
58965f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
58975f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    bool skip = PreCallValidateDestroyCommandPool(dev_data, commandPool, &cp_state);
58985f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    if (!skip) {
58995f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        lock.unlock();
59005f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        dev_data->dispatch_table.DestroyCommandPool(device, commandPool, pAllocator);
59015f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        lock.lock();
5902405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (commandPool != VK_NULL_HANDLE) {
5903405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyCommandPool(dev_data, commandPool, cp_state);
5904405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
59055f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    }
59065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
59075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5908bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL ResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags) {
590956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
591083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
5911400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis
59121ec6311a8537f4467db08eacbd762ebaa87e70b0Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
59139a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pPool = GetCommandPoolNode(dev_data, commandPool);
5914cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis    skip_call |= checkCommandBuffersInFlight(dev_data, pPool, "reset command pool with", VALIDATION_ERROR_00072);
59151ec6311a8537f4467db08eacbd762ebaa87e70b0Chris Forbes    lock.unlock();
5916a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes
5917cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
59185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
59194a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.ResetCommandPool(device, commandPool, flags);
59205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
59215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Reset all of the CBs allocated from this pool
59225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
59231ec6311a8537f4467db08eacbd762ebaa87e70b0Chris Forbes        lock.lock();
5924a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes        clearCommandBuffersInFlight(dev_data, pPool);
5925a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes        for (auto cmdBuffer : pPool->commandBuffers) {
5926a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes            resetCB(dev_data, cmdBuffer);
59275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
59281ec6311a8537f4467db08eacbd762ebaa87e70b0Chris Forbes        lock.unlock();
59295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
59305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
59315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
59325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
593389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL ResetFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences) {
593456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
593583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
5936b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
59375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < fenceCount; ++i) {
59389a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto pFence = GetFenceNode(dev_data, pFences[i]);
5939090da73358f71ba026e2474a822fecf55267d166Chris Forbes        if (pFence && pFence->state == FENCE_INFLIGHT) {
594083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
59414527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 reinterpret_cast<const uint64_t &>(pFences[i]), __LINE__, VALIDATION_ERROR_00183, "DS",
59424527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 "Fence 0x%" PRIx64 " is in use. %s", reinterpret_cast<const uint64_t &>(pFences[i]),
59434527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 validation_error_map[VALIDATION_ERROR_00183]);
59445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
59455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5946b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
5947090da73358f71ba026e2474a822fecf55267d166Chris Forbes
5948cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
5949090da73358f71ba026e2474a822fecf55267d166Chris Forbes
59504a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.ResetFences(device, fenceCount, pFences);
5951090da73358f71ba026e2474a822fecf55267d166Chris Forbes
5952090da73358f71ba026e2474a822fecf55267d166Chris Forbes    if (result == VK_SUCCESS) {
5953090da73358f71ba026e2474a822fecf55267d166Chris Forbes        lock.lock();
5954090da73358f71ba026e2474a822fecf55267d166Chris Forbes        for (uint32_t i = 0; i < fenceCount; ++i) {
59559a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pFence = GetFenceNode(dev_data, pFences[i]);
5956090da73358f71ba026e2474a822fecf55267d166Chris Forbes            if (pFence) {
5957090da73358f71ba026e2474a822fecf55267d166Chris Forbes                pFence->state = FENCE_UNSIGNALED;
5958090da73358f71ba026e2474a822fecf55267d166Chris Forbes            }
5959090da73358f71ba026e2474a822fecf55267d166Chris Forbes        }
5960090da73358f71ba026e2474a822fecf55267d166Chris Forbes        lock.unlock();
5961090da73358f71ba026e2474a822fecf55267d166Chris Forbes    }
5962090da73358f71ba026e2474a822fecf55267d166Chris Forbes
59635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
59645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
59655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5966e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis// For given cb_nodes, invalidate them and track object causing invalidation
59670a4087f99558069e9f6a437ff2dbb5a9c1c22ccaTobin Ehlisvoid invalidateCommandBuffers(const layer_data *dev_data, std::unordered_set<GLOBAL_CB_NODE *> const &cb_nodes, VK_OBJECT obj) {
5968e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis    for (auto cb_node : cb_nodes) {
596939c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis        if (cb_node->state == CB_RECORDING) {
597039c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis            log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
5971fefa20333f94ea75877cca53d0631542cd9d0432Tobin Ehlis                    (uint64_t)(cb_node->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
5972226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    "Invalidating a command buffer that's currently being recorded: 0x%p.", cb_node->commandBuffer);
597339c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis        }
5974e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis        cb_node->state = CB_INVALID;
5975e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis        cb_node->broken_bindings.push_back(obj);
5976e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis    }
5977e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis}
5978e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis
5979c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlisstatic bool PreCallValidateDestroyFramebuffer(layer_data *dev_data, VkFramebuffer framebuffer,
5980c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis                                              FRAMEBUFFER_STATE **framebuffer_state, VK_OBJECT *obj_struct) {
59819a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *framebuffer_state = GetFramebufferState(dev_data, framebuffer);
598294165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(framebuffer), VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT};
5983cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_framebuffer) return false;
5984728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    bool skip = false;
5985728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    if (*framebuffer_state) {
5986728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *framebuffer_state, *obj_struct, VALIDATION_ERROR_00422);
5987728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    }
5988728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    return skip;
5989728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis}
5990728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis
5991c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlisstatic void PostCallRecordDestroyFramebuffer(layer_data *dev_data, VkFramebuffer framebuffer, FRAMEBUFFER_STATE *framebuffer_state,
5992728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis                                             VK_OBJECT obj_struct) {
599339c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, framebuffer_state->cb_bindings, obj_struct);
5994728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    dev_data->frameBufferMap.erase(framebuffer);
5995728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis}
5996728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis
5997bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyFramebuffer(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks *pAllocator) {
599856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5999c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    FRAMEBUFFER_STATE *framebuffer_state = nullptr;
6000728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    VK_OBJECT obj_struct;
6001b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
6002728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    bool skip = PreCallValidateDestroyFramebuffer(dev_data, framebuffer, &framebuffer_state, &obj_struct);
6003728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    if (!skip) {
6004728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis        lock.unlock();
6005728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis        dev_data->dispatch_table.DestroyFramebuffer(device, framebuffer, pAllocator);
6006728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis        lock.lock();
6007405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (framebuffer != VK_NULL_HANDLE) {
6008405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyFramebuffer(dev_data, framebuffer, framebuffer_state, obj_struct);
6009405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
60105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
60115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
60125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
60130ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlisstatic bool PreCallValidateDestroyRenderPass(layer_data *dev_data, VkRenderPass render_pass, RENDER_PASS_STATE **rp_state,
60140ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis                                             VK_OBJECT *obj_struct) {
60159a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *rp_state = GetRenderPassState(dev_data, render_pass);
601694165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(render_pass), VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT};
6017cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_renderpass) return false;
60180ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    bool skip = false;
60190ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    if (*rp_state) {
60200ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *rp_state, *obj_struct, VALIDATION_ERROR_00393);
60210ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    }
60220ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    return skip;
60230ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis}
60240ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis
60250ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlisstatic void PostCallRecordDestroyRenderPass(layer_data *dev_data, VkRenderPass render_pass, RENDER_PASS_STATE *rp_state,
60260ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis                                            VK_OBJECT obj_struct) {
602739c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, rp_state->cb_bindings, obj_struct);
60280ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    dev_data->renderPassMap.erase(render_pass);
60290ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis}
60300ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis
6031bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks *pAllocator) {
603256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
60330ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    RENDER_PASS_STATE *rp_state = nullptr;
60340ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    VK_OBJECT obj_struct;
6035e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
60360ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    bool skip = PreCallValidateDestroyRenderPass(dev_data, renderPass, &rp_state, &obj_struct);
6037a9fbfe0c622e9fa4b56ddd015ed4c3c409020c2eTobin Ehlis    if (!skip) {
6038a9fbfe0c622e9fa4b56ddd015ed4c3c409020c2eTobin Ehlis        lock.unlock();
60394a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyRenderPass(device, renderPass, pAllocator);
60400ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis        lock.lock();
6041405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (renderPass != VK_NULL_HANDLE) {
6042405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyRenderPass(dev_data, renderPass, rp_state, obj_struct);
6043405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
6044a9fbfe0c622e9fa4b56ddd015ed4c3c409020c2eTobin Ehlis    }
60455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
60465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
604789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo,
604889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                            const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer) {
604956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
60503683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    std::unique_lock<std::mutex> lock(global_lock);
60513683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    bool skip = PreCallValidateCreateBuffer(dev_data, pCreateInfo);
60523683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    lock.unlock();
60533683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski
60543683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
60554a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateBuffer(device, pCreateInfo, pAllocator, pBuffer);
60565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
60575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
60583683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski        lock.lock();
60593683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski        PostCallRecordCreateBuffer(dev_data, pCreateInfo, pBuffer);
60603683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski        lock.unlock();
60615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
60625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
60635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
60645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
606589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateBufferView(VkDevice device, const VkBufferViewCreateInfo *pCreateInfo,
606689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                const VkAllocationCallbacks *pAllocator, VkBufferView *pView) {
606756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
60688c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    std::unique_lock<std::mutex> lock(global_lock);
60698c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    bool skip_call = PreCallValidateCreateBufferView(dev_data, pCreateInfo);
60708c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    lock.unlock();
6071cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
60724a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateBufferView(device, pCreateInfo, pAllocator, pView);
60735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
60748c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young        lock.lock();
60753683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski        PostCallRecordCreateBufferView(dev_data, pCreateInfo, pView);
60768c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young        lock.unlock();
60775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
60785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
60795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
60805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
60818dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski// Access helper functions for external modules
6082d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinskiconst VkFormatProperties *GetFormatProperties(core_validation::layer_data *device_data, VkFormat format) {
6083d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    VkFormatProperties *format_properties = new VkFormatProperties;
6084d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    instance_layer_data *instance_data =
6085d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski        GetLayerDataPtr(get_dispatch_key(device_data->instance_data->instance), instance_layer_data_map);
6086d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    instance_data->dispatch_table.GetPhysicalDeviceFormatProperties(device_data->physical_device, format, format_properties);
6087d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    return format_properties;
60888dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski}
60898dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski
6090d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinskiconst VkImageFormatProperties *GetImageFormatProperties(core_validation::layer_data *device_data, VkFormat format,
6091d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski                                                        VkImageType image_type, VkImageTiling tiling, VkImageUsageFlags usage,
6092d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski                                                        VkImageCreateFlags flags) {
6093d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    VkImageFormatProperties *image_format_properties = new VkImageFormatProperties;
6094d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    instance_layer_data *instance_data =
6095d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski        GetLayerDataPtr(get_dispatch_key(device_data->instance_data->instance), instance_layer_data_map);
6096d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    instance_data->dispatch_table.GetPhysicalDeviceImageFormatProperties(device_data->physical_device, format, image_type, tiling,
6097d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski                                                                         usage, flags, image_format_properties);
6098d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    return image_format_properties;
60998dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski}
61008dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski
61018dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinskiconst debug_report_data *GetReportData(core_validation::layer_data *device_data) { return device_data->report_data; }
61028dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski
61038dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinskiconst VkPhysicalDeviceProperties *GetPhysicalDeviceProperties(core_validation::layer_data *device_data) {
61048dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski    return &device_data->phys_dev_props;
61058dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski}
61068dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski
61078c59133586421be878d393799b30044497f77727Mark Lobodzinskiconst CHECK_DISABLED *GetDisables(core_validation::layer_data *device_data) { return &device_data->instance_data->disabled; }
61088c59133586421be878d393799b30044497f77727Mark Lobodzinski
61098c59133586421be878d393799b30044497f77727Mark Lobodzinskistd::unordered_map<VkImage, std::unique_ptr<IMAGE_STATE>> *GetImageMap(core_validation::layer_data *device_data) {
61108c59133586421be878d393799b30044497f77727Mark Lobodzinski    return &device_data->imageMap;
61118c59133586421be878d393799b30044497f77727Mark Lobodzinski}
61128c59133586421be878d393799b30044497f77727Mark Lobodzinski
61138c59133586421be878d393799b30044497f77727Mark Lobodzinskistd::unordered_map<VkImage, std::vector<ImageSubresourcePair>> *GetImageSubresourceMap(core_validation::layer_data *device_data) {
61148c59133586421be878d393799b30044497f77727Mark Lobodzinski    return &device_data->imageSubresourceMap;
61158c59133586421be878d393799b30044497f77727Mark Lobodzinski}
61168c59133586421be878d393799b30044497f77727Mark Lobodzinski
61178c59133586421be878d393799b30044497f77727Mark Lobodzinskistd::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> *GetImageLayoutMap(layer_data *device_data) {
61188c59133586421be878d393799b30044497f77727Mark Lobodzinski    return &device_data->imageLayoutMap;
61198c59133586421be878d393799b30044497f77727Mark Lobodzinski}
61208c59133586421be878d393799b30044497f77727Mark Lobodzinski
61213683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinskistd::unordered_map<VkBuffer, std::unique_ptr<BUFFER_STATE>> *GetBufferMap(layer_data *device_data) {
61223683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    return &device_data->bufferMap;
61233683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski}
61243683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski
61253683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinskistd::unordered_map<VkBufferView, std::unique_ptr<BUFFER_VIEW_STATE>> *GetBufferViewMap(layer_data *device_data) {
61263683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    return &device_data->bufferViewMap;
61273683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski}
61283683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski
61291c143ebdb651ea034e0b1f8731cb9f361e2f8b82Mark Lobodzinskistd::unordered_map<VkImageView, std::unique_ptr<IMAGE_VIEW_STATE>> *GetImageViewMap(layer_data *device_data) {
61301c143ebdb651ea034e0b1f8731cb9f361e2f8b82Mark Lobodzinski    return &device_data->imageViewMap;
61311c143ebdb651ea034e0b1f8731cb9f361e2f8b82Mark Lobodzinski}
61321c143ebdb651ea034e0b1f8731cb9f361e2f8b82Mark Lobodzinski
6133d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinskiconst PHYS_DEV_PROPERTIES_NODE *GetPhysDevProperties(const layer_data *device_data) {
61346a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    return &device_data->phys_dev_properties;
61356a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski}
61366a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski
613789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo,
613889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                           const VkAllocationCallbacks *pAllocator, VkImage *pImage) {
61398dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
614056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
61418dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski    bool skip = PreCallValidateCreateImage(dev_data, pCreateInfo, pAllocator, pImage);
61428dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski    if (!skip) {
61438dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski        result = dev_data->dispatch_table.CreateImage(device, pCreateInfo, pAllocator, pImage);
61448dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski    }
61455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6146b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
6147920311b6aa5614a545cad59521770d0898a75d65Mark Lobodzinski        PostCallRecordCreateImage(dev_data, pCreateInfo, pImage);
61485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
61495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
61505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
61515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
61528c07a094dc9cc4afb6b62181f341c12b9e969041Mark YoungVKAPI_ATTR VkResult VKAPI_CALL CreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo,
61538c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young                                               const VkAllocationCallbacks *pAllocator, VkImageView *pView) {
615456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
61558c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    std::unique_lock<std::mutex> lock(global_lock);
6156e3effabf8e97cae8e006477806ceaca62e4f2ce7Tobin Ehlis    bool skip = PreCallValidateCreateImageView(dev_data, pCreateInfo);
61578c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    lock.unlock();
6158cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
61594a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateImageView(device, pCreateInfo, pAllocator, pView);
61605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
61618c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young        lock.lock();
616279fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis        PostCallRecordCreateImageView(dev_data, pCreateInfo, *pView);
61638c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young        lock.unlock();
61645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6165bb6624cb996175d8945190886a200e720b3871efChris Forbes
61665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
61675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
61685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6169bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateFence(VkDevice device, const VkFenceCreateInfo *pCreateInfo,
6170bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           const VkAllocationCallbacks *pAllocator, VkFence *pFence) {
617156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
61724a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateFence(device, pCreateInfo, pAllocator, pFence);
61735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6174b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
6175a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        auto &fence_node = dev_data->fenceMap[*pFence];
61768988ad37ea5a054ff2ae3cbe4b767ae6c13cf48bChris Forbes        fence_node.fence = *pFence;
6177a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        fence_node.createInfo = *pCreateInfo;
6178cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes        fence_node.state = (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) ? FENCE_RETIRED : FENCE_UNSIGNALED;
61795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
61805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
61815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
61825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
61835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// TODO handle pipeline caches
618489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreatePipelineCache(VkDevice device, const VkPipelineCacheCreateInfo *pCreateInfo,
618589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                   const VkAllocationCallbacks *pAllocator, VkPipelineCache *pPipelineCache) {
618656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
61874a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreatePipelineCache(device, pCreateInfo, pAllocator, pPipelineCache);
61885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
61895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
61905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6191bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyPipelineCache(VkDevice device, VkPipelineCache pipelineCache,
6192bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkAllocationCallbacks *pAllocator) {
619356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
61944a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.DestroyPipelineCache(device, pipelineCache, pAllocator);
61955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
61965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6197bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL GetPipelineCacheData(VkDevice device, VkPipelineCache pipelineCache, size_t *pDataSize,
6198bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                    void *pData) {
619956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
62004a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.GetPipelineCacheData(device, pipelineCache, pDataSize, pData);
62015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
62025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
62035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6204bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL MergePipelineCaches(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount,
6205bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   const VkPipelineCache *pSrcCaches) {
620656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
62074a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.MergePipelineCaches(device, dstCache, srcCacheCount, pSrcCaches);
62085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
62095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
62105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
62113d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis// utility function to set collective state for pipeline
62124c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisvoid set_pipeline_state(PIPELINE_STATE *pPipe) {
62133d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    // If any attachment used by this pipeline has blendEnable, set top-level blendEnable
62143d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    if (pPipe->graphicsPipelineCI.pColorBlendState) {
62153d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        for (size_t i = 0; i < pPipe->attachments.size(); ++i) {
62163d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis            if (VK_TRUE == pPipe->attachments[i].blendEnable) {
62173d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                if (((pPipe->attachments[i].dstAlphaBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
62183d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                     (pPipe->attachments[i].dstAlphaBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
62193d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                    ((pPipe->attachments[i].dstColorBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
62203d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                     (pPipe->attachments[i].dstColorBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
62213d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                    ((pPipe->attachments[i].srcAlphaBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
62223d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                     (pPipe->attachments[i].srcAlphaBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
62233d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                    ((pPipe->attachments[i].srcColorBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
62243d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                     (pPipe->attachments[i].srcColorBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA))) {
62253d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                    pPipe->blendConstantsEnabled = true;
62263d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                }
62273d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis            }
62283d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        }
62293d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
62303d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis}
62313d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis
623248b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinskistatic bool PreCallCreateGraphicsPipelines(layer_data *device_data, uint32_t count,
623348b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski                                           const VkGraphicsPipelineCreateInfo *create_infos, vector<PIPELINE_STATE *> &pipe_state) {
623448b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski    bool skip = false;
6235bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    instance_layer_data *instance_data =
623656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        GetLayerDataPtr(get_dispatch_key(device_data->instance_data->instance), instance_layer_data_map);
623748b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski
623848b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski    for (uint32_t i = 0; i < count; i++) {
623948b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski        skip |= verifyPipelineCreateState(device_data, pipe_state, i);
624078b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski        if (create_infos[i].pVertexInputState != NULL) {
624178b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski            for (uint32_t j = 0; j < create_infos[i].pVertexInputState->vertexAttributeDescriptionCount; j++) {
624278b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                VkFormat format = create_infos[i].pVertexInputState->pVertexAttributeDescriptions[j].format;
624378b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                // Internal call to get format info.  Still goes through layers, could potentially go directly to ICD.
624478b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                VkFormatProperties properties;
624578b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                instance_data->dispatch_table.GetPhysicalDeviceFormatProperties(device_data->physical_device, format, &properties);
624678b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                if ((properties.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT) == 0) {
624778b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                    skip |= log_msg(
624878b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                        device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
624978b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                        __LINE__, VALIDATION_ERROR_01413, "IMAGE",
625078b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                        "vkCreateGraphicsPipelines: pCreateInfo[%d].pVertexInputState->vertexAttributeDescriptions[%d].format "
625178b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                        "(%s) is not a supported vertex buffer format. %s",
625278b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                        i, j, string_VkFormat(format), validation_error_map[VALIDATION_ERROR_01413]);
625378b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                }
625478b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski            }
625578b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski        }
625648b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski    }
625748b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski    return skip;
625848b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski}
625948b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski
6260bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
6261bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                       const VkGraphicsPipelineCreateInfo *pCreateInfos,
6262bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                       const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) {
62635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO What to do with pipelineCache?
62645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // The order of operations here is a little convoluted but gets the job done
62654c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    //  1. Pipeline create state is first shadowed into PIPELINE_STATE struct
62665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    //  2. Create state is then validated (which uses flags setup during shadowing)
62675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    //  3. If everything looks good, we'll then create the pipeline and add NODE to pipelineMap
626842486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski    bool skip = false;
62695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO : Improve this data struct w/ unique_ptrs so cleanup below is automatic
627042486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski    vector<PIPELINE_STATE *> pipe_state(count);
627156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
62725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
62735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t i = 0;
6274b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
62755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
62765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (i = 0; i < count; i++) {
627742486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski        pipe_state[i] = new PIPELINE_STATE;
627842486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski        pipe_state[i]->initGraphicsPipeline(&pCreateInfos[i]);
62799a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        pipe_state[i]->render_pass_ci.initialize(GetRenderPassState(dev_data, pCreateInfos[i].renderPass)->createInfo.ptr());
628042486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski        pipe_state[i]->pipeline_layout = *getPipelineLayout(dev_data, pCreateInfos[i].layout);
62815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
628242486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski    skip |= PreCallCreateGraphicsPipelines(dev_data, count, pCreateInfos, pipe_state);
62835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6284c70226063be6148056ceeccf835175a1fd59f24fChris Forbes    if (skip) {
6285c70226063be6148056ceeccf835175a1fd59f24fChris Forbes        for (i = 0; i < count; i++) {
6286c70226063be6148056ceeccf835175a1fd59f24fChris Forbes            delete pipe_state[i];
62871ab616b32d4e5b7d62d4a8c41b0c03ea335ab845Chris Forbes            pPipelines[i] = VK_NULL_HANDLE;
6288c70226063be6148056ceeccf835175a1fd59f24fChris Forbes        }
62897a456d188475c23b566334be45dc0489b2789653Chris Forbes        return VK_ERROR_VALIDATION_FAILED_EXT;
62907a456d188475c23b566334be45dc0489b2789653Chris Forbes    }
62917a456d188475c23b566334be45dc0489b2789653Chris Forbes
62927a456d188475c23b566334be45dc0489b2789653Chris Forbes    lock.unlock();
6293bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result =
6294bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        dev_data->dispatch_table.CreateGraphicsPipelines(device, pipelineCache, count, pCreateInfos, pAllocator, pPipelines);
62957a456d188475c23b566334be45dc0489b2789653Chris Forbes    lock.lock();
62967a456d188475c23b566334be45dc0489b2789653Chris Forbes    for (i = 0; i < count; i++) {
629761943a7503bc8594338f3364ef42f1d863486c04Chris Forbes        if (pPipelines[i] == VK_NULL_HANDLE) {
629861943a7503bc8594338f3364ef42f1d863486c04Chris Forbes            delete pipe_state[i];
6299bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        } else {
630061943a7503bc8594338f3364ef42f1d863486c04Chris Forbes            pipe_state[i]->pipeline = pPipelines[i];
630161943a7503bc8594338f3364ef42f1d863486c04Chris Forbes            dev_data->pipelineMap[pipe_state[i]->pipeline] = pipe_state[i];
630261943a7503bc8594338f3364ef42f1d863486c04Chris Forbes        }
63035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6304c70226063be6148056ceeccf835175a1fd59f24fChris Forbes
63055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
63065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
63075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6308bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
6309bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      const VkComputePipelineCreateInfo *pCreateInfos,
6310bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) {
63110108a1af0b7c6949846e9d71d00bbfb322b6f7caChris Forbes    bool skip = false;
63125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
63135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO : Improve this data struct w/ unique_ptrs so cleanup below is automatic
63144c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    vector<PIPELINE_STATE *> pPipeState(count);
631556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
63165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
63175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t i = 0;
6318b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
63195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (i = 0; i < count; i++) {
63205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // TODO: Verify compute stage bits
63215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
63225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Create and initialize internal tracking data structure
63234c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis        pPipeState[i] = new PIPELINE_STATE;
63244c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis        pPipeState[i]->initComputePipeline(&pCreateInfos[i]);
6325c2a5a36d03bbe52f5854a5884346e4a84115e259Tobin Ehlis        pPipeState[i]->pipeline_layout = *getPipelineLayout(dev_data, pCreateInfos[i].layout);
63265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
63275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // TODO: Add Compute Pipeline Verification
63280108a1af0b7c6949846e9d71d00bbfb322b6f7caChris Forbes        skip |= !validate_compute_pipeline(dev_data->report_data, pPipeState[i], &dev_data->enabled_features,
6329bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           dev_data->shaderModuleMap);
63300108a1af0b7c6949846e9d71d00bbfb322b6f7caChris Forbes        // skip |= verifyPipelineCreateState(dev_data, pPipeState[i]);
63315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
63325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
63337a456d188475c23b566334be45dc0489b2789653Chris Forbes    if (skip) {
63345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (i = 0; i < count; i++) {
63355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Clean up any locally allocated data structures
63364c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis            delete pPipeState[i];
6337fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes            pPipelines[i] = VK_NULL_HANDLE;
63385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
63395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return VK_ERROR_VALIDATION_FAILED_EXT;
63405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
63417a456d188475c23b566334be45dc0489b2789653Chris Forbes
63427a456d188475c23b566334be45dc0489b2789653Chris Forbes    lock.unlock();
6343bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result =
6344bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        dev_data->dispatch_table.CreateComputePipelines(device, pipelineCache, count, pCreateInfos, pAllocator, pPipelines);
63457a456d188475c23b566334be45dc0489b2789653Chris Forbes    lock.lock();
63467a456d188475c23b566334be45dc0489b2789653Chris Forbes    for (i = 0; i < count; i++) {
6347fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes        if (pPipelines[i] == VK_NULL_HANDLE) {
6348fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes            delete pPipeState[i];
6349bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        } else {
6350fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes            pPipeState[i]->pipeline = pPipelines[i];
6351fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes            dev_data->pipelineMap[pPipeState[i]->pipeline] = pPipeState[i];
6352fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes        }
63537a456d188475c23b566334be45dc0489b2789653Chris Forbes    }
63547a456d188475c23b566334be45dc0489b2789653Chris Forbes
63555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
63565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
63575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
635889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateSampler(VkDevice device, const VkSamplerCreateInfo *pCreateInfo,
635989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                             const VkAllocationCallbacks *pAllocator, VkSampler *pSampler) {
636056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
63614a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateSampler(device, pCreateInfo, pAllocator, pSampler);
63625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6363b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
6364d31a44af6da568692a73201825459689c9431867Tobin Ehlis        dev_data->samplerMap[*pSampler] = unique_ptr<SAMPLER_STATE>(new SAMPLER_STATE(pSampler, pCreateInfo));
63655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
63665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
63675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
63685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
63690c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlisstatic bool PreCallValidateCreateDescriptorSetLayout(layer_data *dev_data, const VkDescriptorSetLayoutCreateInfo *create_info) {
6370cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.create_descriptor_set_layout) return false;
63710c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    return cvdescriptorset::DescriptorSetLayout::ValidateCreateInfo(dev_data->report_data, create_info);
63720c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis}
63730c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis
63740c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlisstatic void PostCallRecordCreateDescriptorSetLayout(layer_data *dev_data, const VkDescriptorSetLayoutCreateInfo *create_info,
63750c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis                                                    VkDescriptorSetLayout set_layout) {
63763f1d2ba6852cf6b1bb4e1f06d690293565108e2cTobin Ehlis    // TODO: Convert this to unique_ptr to avoid leaks
63770c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    dev_data->descriptorSetLayoutMap[set_layout] = new cvdescriptorset::DescriptorSetLayout(create_info, set_layout);
63780c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis}
63790c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis
6380bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
6381bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                         const VkAllocationCallbacks *pAllocator,
6382bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                         VkDescriptorSetLayout *pSetLayout) {
638356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
63840c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
63850c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
63860c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    bool skip = PreCallValidateCreateDescriptorSetLayout(dev_data, pCreateInfo);
63870c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    if (!skip) {
63880c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis        lock.unlock();
63890c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis        result = dev_data->dispatch_table.CreateDescriptorSetLayout(device, pCreateInfo, pAllocator, pSetLayout);
63900c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis        if (VK_SUCCESS == result) {
63910c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis            lock.lock();
63920c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis            PostCallRecordCreateDescriptorSetLayout(dev_data, pCreateInfo, *pSetLayout);
63930c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis        }
63945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
63955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
63965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
63975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
63989e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz// Used by CreatePipelineLayout and CmdPushConstants.
63999e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz// Note that the index argument is optional and only used by CreatePipelineLayout.
64009e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultzstatic bool validatePushConstantRange(const layer_data *dev_data, const uint32_t offset, const uint32_t size,
64019e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz                                      const char *caller_name, uint32_t index = 0) {
6402cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.push_constant_range) return false;
64039e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    uint32_t const maxPushConstantsSize = dev_data->phys_dev_properties.properties.limits.maxPushConstantsSize;
640483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
64059e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // Check that offset + size don't exceed the max.
64069e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // Prevent arithetic overflow here by avoiding addition and testing in this order.
64079e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    if ((offset >= maxPushConstantsSize) || (size > maxPushConstantsSize - offset)) {
64089e24d8153ab63bc3ac08b5a1517c203930b5de91Karl 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.
64099e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        if (0 == strcmp(caller_name, "vkCreatePipelineLayout()")) {
6410e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis            if (offset >= maxPushConstantsSize) {
6411e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis                skip_call |=
6412e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
6413cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            VALIDATION_ERROR_00877, "DS",
6414cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s call has push constants index %u with offset %u that "
6415cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "exceeds this device's maxPushConstantSize of %u. %s",
6416e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis                            caller_name, index, offset, maxPushConstantsSize, validation_error_map[VALIDATION_ERROR_00877]);
6417e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis            }
6418e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis            if (size > maxPushConstantsSize - offset) {
6419e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis                skip_call |=
6420e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
6421cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            VALIDATION_ERROR_00880, "DS",
6422cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s call has push constants index %u with offset %u and size %u that "
6423cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "exceeds this device's maxPushConstantSize of %u. %s",
6424e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis                            caller_name, index, offset, size, maxPushConstantsSize, validation_error_map[VALIDATION_ERROR_00880]);
6425e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis            }
64269e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else if (0 == strcmp(caller_name, "vkCmdPushConstants()")) {
64274527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            if (offset >= maxPushConstantsSize) {
64284527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                skip_call |=
64294527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
6430cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            VALIDATION_ERROR_00991, "DS",
6431cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s call has push constants index %u with offset %u that "
6432cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "exceeds this device's maxPushConstantSize of %u. %s",
64334527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            caller_name, index, offset, maxPushConstantsSize, validation_error_map[VALIDATION_ERROR_00991]);
64344527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            }
64354527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            if (size > maxPushConstantsSize - offset) {
64364527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                skip_call |=
64374527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
6438cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            VALIDATION_ERROR_00992, "DS",
6439cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s call has push constants index %u with offset %u and size %u that "
6440cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "exceeds this device's maxPushConstantSize of %u. %s",
64414527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            caller_name, index, offset, size, maxPushConstantsSize, validation_error_map[VALIDATION_ERROR_00992]);
64424527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            }
64439e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else {
644483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
644583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 DRAWSTATE_INTERNAL_ERROR, "DS", "%s caller not supported.", caller_name);
64469e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
64479e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    }
64489e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // size needs to be non-zero and a multiple of 4.
64499e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    if ((size == 0) || ((size & 0x3) != 0)) {
64509e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        if (0 == strcmp(caller_name, "vkCreatePipelineLayout()")) {
6451891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis            if (size == 0) {
6452891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
6453cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     __LINE__, VALIDATION_ERROR_00878, "DS",
6454cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "%s call has push constants index %u with "
6455cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "size %u. Size must be greater than zero. %s",
6456891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis                                     caller_name, index, size, validation_error_map[VALIDATION_ERROR_00878]);
6457891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis            }
6458891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis            if (size & 0x3) {
6459891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
6460cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     __LINE__, VALIDATION_ERROR_00879, "DS",
6461cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "%s call has push constants index %u with "
6462cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "size %u. Size must be a multiple of 4. %s",
6463891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis                                     caller_name, index, size, validation_error_map[VALIDATION_ERROR_00879]);
6464891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis            }
64659e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else if (0 == strcmp(caller_name, "vkCmdPushConstants()")) {
64664527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            if (size == 0) {
64674527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
6468cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     __LINE__, VALIDATION_ERROR_01000, "DS",
6469cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "%s call has push constants index %u with "
6470cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "size %u. Size must be greater than zero. %s",
64714527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                     caller_name, index, size, validation_error_map[VALIDATION_ERROR_01000]);
64724527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            }
64734527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            if (size & 0x3) {
64744527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
6475cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     __LINE__, VALIDATION_ERROR_00990, "DS",
6476cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "%s call has push constants index %u with "
6477cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "size %u. Size must be a multiple of 4. %s",
64784527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                     caller_name, index, size, validation_error_map[VALIDATION_ERROR_00990]);
64794527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            }
64809e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else {
648183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
648283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 DRAWSTATE_INTERNAL_ERROR, "DS", "%s caller not supported.", caller_name);
64839e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
64849e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    }
64859e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // offset needs to be a multiple of 4.
64869e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    if ((offset & 0x3) != 0) {
64879e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        if (0 == strcmp(caller_name, "vkCreatePipelineLayout()")) {
648883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
6489cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 VALIDATION_ERROR_02521, "DS",
6490cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "%s call has push constants index %u with "
6491cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "offset %u. Offset must be a multiple of 4. %s",
64924527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 caller_name, index, offset, validation_error_map[VALIDATION_ERROR_02521]);
64939e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else if (0 == strcmp(caller_name, "vkCmdPushConstants()")) {
649483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
6495cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 VALIDATION_ERROR_00989, "DS",
6496cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "%s call has push constants with "
6497cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "offset %u. Offset must be a multiple of 4. %s",
64984527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 caller_name, offset, validation_error_map[VALIDATION_ERROR_00989]);
64999e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else {
650083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
650183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 DRAWSTATE_INTERNAL_ERROR, "DS", "%s caller not supported.", caller_name);
65029e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
65035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
650483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
65055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
65065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6507bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo *pCreateInfo,
650889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                    const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout) {
650983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
651056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
65111c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis    // TODO : Add checks for VALIDATION_ERRORS 865-871
65129e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // Push Constant Range checks
651307a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz    uint32_t i, j;
65145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
651583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis        skip_call |= validatePushConstantRange(dev_data, pCreateInfo->pPushConstantRanges[i].offset,
651683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                               pCreateInfo->pPushConstantRanges[i].size, "vkCreatePipelineLayout()", i);
65179e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        if (0 == pCreateInfo->pPushConstantRanges[i].stageFlags) {
651883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
65194527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 VALIDATION_ERROR_00882, "DS", "vkCreatePipelineLayout() call has no stageFlags set. %s",
65204527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 validation_error_map[VALIDATION_ERROR_00882]);
65219e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
65229e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    }
6523cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
652407a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz
65259e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // Each range has been validated.  Now check for overlap between ranges (if they are good).
652607a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz    // There's no explicit Valid Usage language against this, so issue a warning instead of an error.
652707a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz    for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
652807a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz        for (j = i + 1; j < pCreateInfo->pushConstantRangeCount; ++j) {
652907a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz            const uint32_t minA = pCreateInfo->pPushConstantRanges[i].offset;
653007a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz            const uint32_t maxA = minA + pCreateInfo->pPushConstantRanges[i].size;
653107a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz            const uint32_t minB = pCreateInfo->pPushConstantRanges[j].offset;
653207a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz            const uint32_t maxB = minB + pCreateInfo->pPushConstantRanges[j].size;
653307a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz            if ((minA <= minB && maxA > minB) || (minB <= minA && maxB > minA)) {
6534cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
6535cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     __LINE__, DRAWSTATE_PUSH_CONSTANTS_ERROR, "DS",
6536cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "vkCreatePipelineLayout() call has push constants with "
6537cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "overlapping ranges: %u:[%u, %u), %u:[%u, %u)",
6538cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     i, minA, maxA, j, minB, maxB);
65399e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz            }
65405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
65415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6542f73b2046273413ea1338dd714d67c39f8e0fa09eChris Forbes
65434a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreatePipelineLayout(device, pCreateInfo, pAllocator, pPipelineLayout);
65445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6545b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
65465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        PIPELINE_LAYOUT_NODE &plNode = dev_data->pipelineLayoutMap[*pPipelineLayout];
654769b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis        plNode.layout = *pPipelineLayout;
6548416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis        plNode.set_layouts.resize(pCreateInfo->setLayoutCount);
65495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (i = 0; i < pCreateInfo->setLayoutCount; ++i) {
65509a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            plNode.set_layouts[i] = GetDescriptorSetLayout(dev_data, pCreateInfo->pSetLayouts[i]);
65515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6552416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis        plNode.push_constant_ranges.resize(pCreateInfo->pushConstantRangeCount);
65535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
6554416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis            plNode.push_constant_ranges[i] = pCreateInfo->pPushConstantRanges[i];
65555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
65565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
65575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
65585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
65595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6560bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateDescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo *pCreateInfo,
6561bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                    const VkAllocationCallbacks *pAllocator, VkDescriptorPool *pDescriptorPool) {
656256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
65634a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateDescriptorPool(device, pCreateInfo, pAllocator, pDescriptorPool);
65645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
65655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
6566414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                    (uint64_t)*pDescriptorPool, __LINE__, DRAWSTATE_OUT_OF_MEMORY, "DS", "Created Descriptor Pool 0x%" PRIxLEAST64,
65675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    (uint64_t)*pDescriptorPool))
65685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return VK_ERROR_VALIDATION_FAILED_EXT;
6569a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis        DESCRIPTOR_POOL_STATE *pNewNode = new DESCRIPTOR_POOL_STATE(*pDescriptorPool, pCreateInfo);
65705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (NULL == pNewNode) {
65715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
65725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        (uint64_t)*pDescriptorPool, __LINE__, DRAWSTATE_OUT_OF_MEMORY, "DS",
6573a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis                        "Out of memory while attempting to allocate DESCRIPTOR_POOL_STATE in vkCreateDescriptorPool()"))
65745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return VK_ERROR_VALIDATION_FAILED_EXT;
65755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
6576b9e992386a44404152747d66817a733aa127e281Jeremy Hayes            std::lock_guard<std::mutex> lock(global_lock);
65775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->descriptorPoolMap[*pDescriptorPool] = pNewNode;
65785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
65795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
65805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Need to do anything if pool create fails?
65815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
65825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
65835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
65845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6585bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL ResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool,
6586bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   VkDescriptorPoolResetFlags flags) {
65877286e20c06011d3c6fa7edfbdbadd42bb6e8cc35Tobin Ehlis    // TODO : Add checks for VALIDATION_ERROR_00928
658856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
65894a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.ResetDescriptorPool(device, descriptorPool, flags);
65905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6591b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
65925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        clearDescriptorPool(dev_data, device, descriptorPool, flags);
65935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
65945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
65955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
65962c4e180a4442f968b44f3d5136f7ffda706f6428Chris Forbes// Ensure the pool contains enough descriptors and descriptor sets to satisfy
6597789832b514862c7a7b5b847eeb8e7cacb733b77bTobin Ehlis// an allocation request. Fills common_data with the total number of descriptors of each type required,
6598789832b514862c7a7b5b847eeb8e7cacb733b77bTobin Ehlis// as well as DescriptorSetLayout ptrs used for later update.
65997f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlisstatic bool PreCallValidateAllocateDescriptorSets(layer_data *dev_data, const VkDescriptorSetAllocateInfo *pAllocateInfo,
66007f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis                                                  cvdescriptorset::AllocateDescriptorSetsData *common_data) {
6601cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.allocate_descriptor_sets) return false;
66027e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlis    // All state checks for AllocateDescriptorSets is done in single function
6603e3f7c45fd64a44a67ce96c89e2bbee426c6ecf24Tobin Ehlis    return cvdescriptorset::ValidateAllocateDescriptorSets(dev_data->report_data, pAllocateInfo, dev_data, common_data);
66047e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlis}
66057e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlis// Allocation state was good and call down chain was made so update state based on allocating descriptor sets
66067e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlisstatic void PostCallRecordAllocateDescriptorSets(layer_data *dev_data, const VkDescriptorSetAllocateInfo *pAllocateInfo,
66077f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis                                                 VkDescriptorSet *pDescriptorSets,
66087f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis                                                 const cvdescriptorset::AllocateDescriptorSetsData *common_data) {
66097e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlis    // All the updates are contained in a single cvdescriptorset function
66102c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    cvdescriptorset::PerformAllocateDescriptorSets(pAllocateInfo, pDescriptorSets, common_data, &dev_data->descriptorPoolMap,
6611b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis                                                   &dev_data->setMap, dev_data);
66122c4e180a4442f968b44f3d5136f7ffda706f6428Chris Forbes}
66132c4e180a4442f968b44f3d5136f7ffda706f6428Chris Forbes
6614bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL AllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo,
6615bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      VkDescriptorSet *pDescriptorSets) {
661656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
6617b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
66187f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis    cvdescriptorset::AllocateDescriptorSetsData common_data(pAllocateInfo->descriptorSetCount);
66197f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis    bool skip_call = PreCallValidateAllocateDescriptorSets(dev_data, pAllocateInfo, &common_data);
6620b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
6621d173e0daab123373ce75105f2a908f6ae7cef6abChris Forbes
6622cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
6623d173e0daab123373ce75105f2a908f6ae7cef6abChris Forbes
66244a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.AllocateDescriptorSets(device, pAllocateInfo, pDescriptorSets);
66256511ce241f7f210211e0c0e882f3c14889071f4dChris Forbes
66265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6627b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
66287f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis        PostCallRecordAllocateDescriptorSets(dev_data, pAllocateInfo, pDescriptorSets, &common_data);
6629b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
66305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
66315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
66325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
6633cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis// Verify state before freeing DescriptorSets
6634cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlisstatic bool PreCallValidateFreeDescriptorSets(const layer_data *dev_data, VkDescriptorPool pool, uint32_t count,
6635cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis                                              const VkDescriptorSet *descriptor_sets) {
6636cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.free_descriptor_sets) return false;
6637cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    bool skip_call = false;
6638cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    // First make sure sets being destroyed are not currently in-use
6639405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour    for (uint32_t i = 0; i < count; ++i) {
6640405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (descriptor_sets[i] != VK_NULL_HANDLE) {
6641405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            skip_call |= validateIdleDescriptorSet(dev_data, descriptor_sets[i], "vkFreeDescriptorSets");
6642405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
6643405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour    }
6644cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis
66459a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DESCRIPTOR_POOL_STATE *pool_state = GetDescriptorPoolState(dev_data, pool);
6646a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis    if (pool_state && !(VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT & pool_state->createInfo.flags)) {
6647cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis        // Can't Free from a NON_FREE pool
6648cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
66491c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis                             reinterpret_cast<uint64_t &>(pool), __LINE__, VALIDATION_ERROR_00922, "DS",
6650cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis                             "It is invalid to call vkFreeDescriptorSets() with a pool created without setting "
66511c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis                             "VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT. %s",
66521c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis                             validation_error_map[VALIDATION_ERROR_00922]);
6653cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    }
6654cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    return skip_call;
6655cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis}
6656cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis// Sets have been removed from the pool so update underlying state
6657cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlisstatic void PostCallRecordFreeDescriptorSets(layer_data *dev_data, VkDescriptorPool pool, uint32_t count,
6658cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis                                             const VkDescriptorSet *descriptor_sets) {
66599a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DESCRIPTOR_POOL_STATE *pool_state = GetDescriptorPoolState(dev_data, pool);
6660cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    // Update available descriptor sets in pool
6661cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    pool_state->availableSets += count;
6662cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis
6663cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    // For each freed descriptor add its resources back into the pool as available and remove from pool and setMap
6664cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    for (uint32_t i = 0; i < count; ++i) {
6665405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (descriptor_sets[i] != VK_NULL_HANDLE) {
6666405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            auto descriptor_set = dev_data->setMap[descriptor_sets[i]];
6667405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            uint32_t type_index = 0, descriptor_count = 0;
6668405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            for (uint32_t j = 0; j < descriptor_set->GetBindingCount(); ++j) {
6669405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour                type_index = static_cast<uint32_t>(descriptor_set->GetTypeFromIndex(j));
6670405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour                descriptor_count = descriptor_set->GetDescriptorCountFromIndex(j);
6671405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour                pool_state->availableDescriptorTypeCount[type_index] += descriptor_count;
6672405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            }
6673405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            freeDescriptorSet(dev_data, descriptor_set);
6674405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            pool_state->sets.erase(descriptor_set);
6675405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
6676cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    }
6677cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis}
66785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6679bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL FreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t count,
6680bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                  const VkDescriptorSet *pDescriptorSets) {
668156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
66825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Make sure that no sets being destroyed are in-flight
6683b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
668483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = PreCallValidateFreeDescriptorSets(dev_data, descriptorPool, count, pDescriptorSets);
6685b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
6686e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis
6687cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
66884a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.FreeDescriptorSets(device, descriptorPool, count, pDescriptorSets);
66895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6690b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
6691cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis        PostCallRecordFreeDescriptorSets(dev_data, descriptorPool, count, pDescriptorSets);
6692b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
66935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
66945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
66955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
66966b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis// TODO : This is a Proof-of-concept for core validation architecture
66976b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis//  Really we'll want to break out these functions to separate files but
66986b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis//  keeping it all together here to prove out design
66996b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis// PreCallValidate* handles validating all of the state prior to calling down chain to UpdateDescriptorSets()
67006b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlisstatic bool PreCallValidateUpdateDescriptorSets(layer_data *dev_data, uint32_t descriptorWriteCount,
67016b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                                const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
67026b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                                const VkCopyDescriptorSet *pDescriptorCopies) {
6703cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.update_descriptor_sets) return false;
67046b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // First thing to do is perform map look-ups.
67056b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // NOTE : UpdateDescriptorSets is somewhat unique in that it's operating on a number of DescriptorSets
67066b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    //  so we can't just do a single map look-up up-front, but do them individually in functions below
67076b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis
67086b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // Now make call(s) that validate state, but don't perform state updates in this function
67096b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // Note, here DescriptorSets is unique in that we don't yet have an instance. Using a helper function in the
67106b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    //  namespace which will parse params and make calls into specific class instances
6711104ab082916e41467ef60baaab7a5a8b2e02c59cTobin Ehlis    return cvdescriptorset::ValidateUpdateDescriptorSets(dev_data->report_data, dev_data, descriptorWriteCount, pDescriptorWrites,
6712104ab082916e41467ef60baaab7a5a8b2e02c59cTobin Ehlis                                                         descriptorCopyCount, pDescriptorCopies);
67136b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis}
67146b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis// PostCallRecord* handles recording state updates following call down chain to UpdateDescriptorSets()
67156b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlisstatic void PostCallRecordUpdateDescriptorSets(layer_data *dev_data, uint32_t descriptorWriteCount,
67166b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                               const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
67176b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                               const VkCopyDescriptorSet *pDescriptorCopies) {
6718104ab082916e41467ef60baaab7a5a8b2e02c59cTobin Ehlis    cvdescriptorset::PerformUpdateDescriptorSets(dev_data, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
67196b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                                 pDescriptorCopies);
67206b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis}
67215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6722bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL UpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount,
6723bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
6724bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkCopyDescriptorSet *pDescriptorCopies) {
67256b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // Only map look-up at top level is for device-level layer_data
672656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
6727b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
67286b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    bool skip_call = PreCallValidateUpdateDescriptorSets(dev_data, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
67296b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                                         pDescriptorCopies);
6730b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
67316b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    if (!skip_call) {
67324a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.UpdateDescriptorSets(device, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
67334a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                      pDescriptorCopies);
67346b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis        lock.lock();
67356b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis        // Since UpdateDescriptorSets() is void, nothing to check prior to updating state
67366b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis        PostCallRecordUpdateDescriptorSets(dev_data, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
67376b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                           pDescriptorCopies);
67385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
67395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
67405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6741bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL AllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pCreateInfo,
6742bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      VkCommandBuffer *pCommandBuffer) {
674356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
67444a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.AllocateCommandBuffers(device, pCreateInfo, pCommandBuffer);
67455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6746b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::unique_lock<std::mutex> lock(global_lock);
67479a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto pPool = GetCommandPoolNode(dev_data, pCreateInfo->commandPool);
6748cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes
6749cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes        if (pPool) {
675072d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis            for (uint32_t i = 0; i < pCreateInfo->commandBufferCount; i++) {
67515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // Add command buffer to its commandPool map
6752cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes                pPool->commandBuffers.push_back(pCommandBuffer[i]);
67535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                GLOBAL_CB_NODE *pCB = new GLOBAL_CB_NODE;
67545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // Add command buffer to map
67555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                dev_data->commandBufferMap[pCommandBuffer[i]] = pCB;
67565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                resetCB(dev_data, pCommandBuffer[i]);
67575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pCB->createInfo = *pCreateInfo;
67585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pCB->device = device;
67595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
67605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6761b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
67625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
67635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
67645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
67655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6766883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis// Add bindings between the given cmd buffer & framebuffer and the framebuffer's children
6767c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlisstatic void AddFramebufferBinding(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, FRAMEBUFFER_STATE *fb_state) {
67680245b74a083d2cb3b083571deb0fe13b4ab428a4Tobin Ehlis    addCommandBufferBinding(&fb_state->cb_bindings,
67690245b74a083d2cb3b083571deb0fe13b4ab428a4Tobin Ehlis                            {reinterpret_cast<uint64_t &>(fb_state->framebuffer), VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT},
67700245b74a083d2cb3b083571deb0fe13b4ab428a4Tobin Ehlis                            cb_state);
6771883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis    for (auto attachment : fb_state->attachments) {
6772883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        auto view_state = attachment.view_state;
6773883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        if (view_state) {
677403ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis            AddCommandBufferBindingImageView(dev_data, cb_state, view_state);
6775883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        }
67769a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto rp_state = GetRenderPassState(dev_data, fb_state->createInfo.renderPass);
6777883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        if (rp_state) {
6778883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis            addCommandBufferBinding(
6779883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis                &rp_state->cb_bindings,
6780883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis                {reinterpret_cast<uint64_t &>(rp_state->renderPass), VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT}, cb_state);
6781883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        }
6782883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis    }
6783883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis}
6784883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis
6785bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL BeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo) {
678683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
678756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6788b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
67895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Validate command buffer level
67909a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *cb_node = GetCBNode(dev_data, commandBuffer);
6791f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis    if (cb_node) {
67925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // This implicitly resets the Cmd Buffer so make sure any fence is done and then clear memory references
6793a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        if (dev_data->globalInFlightCmdBuffers.count(commandBuffer)) {
679483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |=
6795a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
67964527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                        (uint64_t)commandBuffer, __LINE__, VALIDATION_ERROR_00104, "MEM",
6797d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen                        "Calling vkBeginCommandBuffer() on active command buffer 0x%p before it has completed. "
67984527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                        "You must check command buffer fence before this call. %s",
67994527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                        commandBuffer, validation_error_map[VALIDATION_ERROR_00104]);
68005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6801f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        clear_cmd_buf_and_mem_references(dev_data, cb_node);
6802f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        if (cb_node->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
68035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Secondary Command Buffer
68045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            const VkCommandBufferInheritanceInfo *pInfo = pBeginInfo->pInheritanceInfo;
68055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!pInfo) {
680683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                skip_call |=
68075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
68084527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            reinterpret_cast<uint64_t>(commandBuffer), __LINE__, VALIDATION_ERROR_00106, "DS",
6809bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "vkBeginCommandBuffer(): Secondary Command Buffer (0x%p) must have inheritance info. %s", commandBuffer,
6810bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            validation_error_map[VALIDATION_ERROR_00106]);
68115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else {
68125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (pBeginInfo->flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT) {
68132c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                    // Object_tracker makes sure these objects are valid
68142c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                    assert(pInfo->renderPass);
68152c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                    assert(pInfo->framebuffer);
68162c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                    string errorString = "";
68179a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto framebuffer = GetFramebufferState(dev_data, pInfo->framebuffer);
68182c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                    if (framebuffer) {
68192c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                        if ((framebuffer->createInfo.renderPass != pInfo->renderPass) &&
68202c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                            !verify_renderpass_compatibility(dev_data, framebuffer->renderPassCreateInfo.ptr(),
68219a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                                                             GetRenderPassState(dev_data, pInfo->renderPass)->createInfo.ptr(),
68222c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                             errorString)) {
68232c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                            // renderPass that framebuffer was created with must be compatible with local renderPass
68242c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
68252c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
68262c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                 reinterpret_cast<uint64_t>(commandBuffer), __LINE__, VALIDATION_ERROR_00112, "DS",
68272c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                 "vkBeginCommandBuffer(): Secondary Command "
6828cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                 "Buffer (0x%p) renderPass (0x%" PRIxLEAST64
6829cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                 ") is incompatible w/ framebuffer "
68302c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                 "(0x%" PRIxLEAST64 ") w/ render pass (0x%" PRIxLEAST64 ") due to: %s. %s",
68312c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                 commandBuffer, reinterpret_cast<const uint64_t &>(pInfo->renderPass),
68322c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                 reinterpret_cast<const uint64_t &>(pInfo->framebuffer),
68332c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                 reinterpret_cast<uint64_t &>(framebuffer->createInfo.renderPass),
68342c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                 errorString.c_str(), validation_error_map[VALIDATION_ERROR_00112]);
68355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        }
68362c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                        // Connect this framebuffer and its children to this cmdBuffer
68372c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                        AddFramebufferBinding(dev_data, cb_node, framebuffer);
68385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
68395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
68404527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                if ((pInfo->occlusionQueryEnable == VK_FALSE || dev_data->enabled_features.occlusionQueryPrecise == VK_FALSE) &&
68415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    (pInfo->queryFlags & VK_QUERY_CONTROL_PRECISE_BIT)) {
684283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
684383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                         VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t>(commandBuffer),
68444527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                         __LINE__, VALIDATION_ERROR_00107, "DS",
684583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                         "vkBeginCommandBuffer(): Secondary Command Buffer (0x%p) must not have "
684683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                         "VK_QUERY_CONTROL_PRECISE_BIT if occulusionQuery is disabled or the device does not "
68474527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                         "support precise occlusion queries. %s",
68484527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                         commandBuffer, validation_error_map[VALIDATION_ERROR_00107]);
68495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
68505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
68515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (pInfo && pInfo->renderPass != VK_NULL_HANDLE) {
68529a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto renderPass = GetRenderPassState(dev_data, pInfo->renderPass);
685316387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                if (renderPass) {
6854fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes                    if (pInfo->subpass >= renderPass->createInfo.subpassCount) {
685583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                        skip_call |= log_msg(
6856bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6857bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            (uint64_t)commandBuffer, __LINE__, VALIDATION_ERROR_00111, "DS",
68584527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            "vkBeginCommandBuffer(): Secondary Command Buffers (0x%p) must have a subpass index (%d) "
68594527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            "that is less than the number of subpasses (%d). %s",
68604527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            commandBuffer, pInfo->subpass, renderPass->createInfo.subpassCount,
68614527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            validation_error_map[VALIDATION_ERROR_00111]);
68625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
68635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
68645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
68655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6866f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        if (CB_RECORDING == cb_node->state) {
6867cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            skip_call |=
6868cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6869cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        (uint64_t)commandBuffer, __LINE__, VALIDATION_ERROR_00103, "DS",
6870cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "vkBeginCommandBuffer(): Cannot call Begin on command buffer (0x%p"
6871cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        ") in the RECORDING state. Must first call vkEndCommandBuffer(). %s",
6872cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        commandBuffer, validation_error_map[VALIDATION_ERROR_00103]);
6873347d4d3139a1e743ed85bd375c20fd35bbe68d74Chris Forbes        } else if (CB_RECORDED == cb_node->state || (CB_INVALID == cb_node->state && CMD_END == cb_node->last_cmd)) {
6874f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            VkCommandPool cmdPool = cb_node->createInfo.commandPool;
68759a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pPool = GetCommandPoolNode(dev_data, cmdPool);
6876cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes            if (!(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT & pPool->createFlags)) {
687783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                skip_call |=
68785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
68794527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            (uint64_t)commandBuffer, __LINE__, VALIDATION_ERROR_00105, "DS",
6880226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                            "Call to vkBeginCommandBuffer() on command buffer (0x%p"
6881414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                            ") attempts to implicitly reset cmdBuffer created from command pool (0x%" PRIxLEAST64
68824527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            ") that does NOT have the VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT bit set. %s",
68834527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            commandBuffer, (uint64_t)cmdPool, validation_error_map[VALIDATION_ERROR_00105]);
68845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
68855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            resetCB(dev_data, commandBuffer);
68865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
68875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Set updated state here in case implicit reset occurs above
6888f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        cb_node->state = CB_RECORDING;
6889f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        cb_node->beginInfo = *pBeginInfo;
6890f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        if (cb_node->beginInfo.pInheritanceInfo) {
6891f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->inheritanceInfo = *(cb_node->beginInfo.pInheritanceInfo);
6892f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->beginInfo.pInheritanceInfo = &cb_node->inheritanceInfo;
6893888e1d268098177fde4a2263e3d7b7cc415f1debMark Young            // If we are a secondary command-buffer and inheriting.  Update the items we should inherit.
6894f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            if ((cb_node->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) &&
6895f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                (cb_node->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
68969a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                cb_node->activeRenderPass = GetRenderPassState(dev_data, cb_node->beginInfo.pInheritanceInfo->renderPass);
6897f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                cb_node->activeSubpass = cb_node->beginInfo.pInheritanceInfo->subpass;
6898350841afb70bf8dcfc3c6ec6b66f0aaa639553a3Tobin Ehlis                cb_node->activeFramebuffer = cb_node->beginInfo.pInheritanceInfo->framebuffer;
6899f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                cb_node->framebuffers.insert(cb_node->beginInfo.pInheritanceInfo->framebuffer);
6900888e1d268098177fde4a2263e3d7b7cc415f1debMark Young            }
69015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
69025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6903b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
690483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (skip_call) {
69055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return VK_ERROR_VALIDATION_FAILED_EXT;
69065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
69074a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.BeginCommandBuffer(commandBuffer, pBeginInfo);
6908400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis
69095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
69105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
69115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
691289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL EndCommandBuffer(VkCommandBuffer commandBuffer) {
691383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
69145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_SUCCESS;
691556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6916b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
69179a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
69185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
69194527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton        if ((VK_COMMAND_BUFFER_LEVEL_PRIMARY == pCB->createInfo.level) ||
69204527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
6921fd61966f8d41b5bce15620b70563b7864cbb28feCody Northrop            // This needs spec clarification to update valid usage, see comments in PR:
6922fd61966f8d41b5bce15620b70563b7864cbb28feCody Northrop            // https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/pull/516#discussion_r63013756
6923ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen            skip_call |= insideRenderPass(dev_data, pCB, "vkEndCommandBuffer()", VALIDATION_ERROR_00123);
6924fd61966f8d41b5bce15620b70563b7864cbb28feCody Northrop        }
692529f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_END, "vkEndCommandBuffer()");
69261ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_END);
69275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto query : pCB->activeQueries) {
692883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
69294527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 VALIDATION_ERROR_00124, "DS",
69304527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 "Ending command buffer with in progress query: queryPool 0x%" PRIx64 ", index %d. %s",
69314527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 (uint64_t)(query.pool), query.index, validation_error_map[VALIDATION_ERROR_00124]);
69325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
69335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
693483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (!skip_call) {
6935b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
69364a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.EndCommandBuffer(commandBuffer);
6937b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
69385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (VK_SUCCESS == result) {
69395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pCB->state = CB_RECORDED;
69405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Reset CB status flags
69415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pCB->status = 0;
69425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
69435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
69445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        result = VK_ERROR_VALIDATION_FAILED_EXT;
69455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6946b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
69475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
69485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
69495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6950bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL ResetCommandBuffer(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags) {
6951bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    bool skip_call = false;
695256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6953b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
69549a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
69555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkCommandPool cmdPool = pCB->createInfo.commandPool;
69569a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pPool = GetCommandPoolNode(dev_data, cmdPool);
6957cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes    if (!(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT & pPool->createFlags)) {
6958bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
69594527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                             (uint64_t)commandBuffer, __LINE__, VALIDATION_ERROR_00093, "DS",
6960226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                             "Attempt to reset command buffer (0x%p) created from command pool (0x%" PRIxLEAST64
69614527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                             ") that does NOT have the VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT bit set. %s",
69624527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                             commandBuffer, (uint64_t)cmdPool, validation_error_map[VALIDATION_ERROR_00093]);
69635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6964cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis    skip_call |= checkCommandBufferInFlight(dev_data, pCB, "reset", VALIDATION_ERROR_00092);
6965b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
6966cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
69674a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.ResetCommandBuffer(commandBuffer, flags);
69685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6969b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
6970a964cad279f9749cd9ebfc7555247ff3bff26d53Chris Forbes        dev_data->globalInFlightCmdBuffers.erase(commandBuffer);
69715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        resetCB(dev_data, commandBuffer);
6972b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
69735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
69745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
69755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
697693c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski
6977bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBindPipeline(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
6978bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           VkPipeline pipeline) {
6979e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis    bool skip = false;
698056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6981b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
69829a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
6983e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis    if (cb_state) {
698429f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip |= ValidateCmd(dev_data, cb_state, CMD_BINDPIPELINE, "vkCmdBindPipeline()");
69851ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(cb_state, CMD_BINDPIPELINE);
6986e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        if ((VK_PIPELINE_BIND_POINT_COMPUTE == pipelineBindPoint) && (cb_state->activeRenderPass)) {
6987e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            skip |=
69885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
69895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        (uint64_t)pipeline, __LINE__, DRAWSTATE_INVALID_RENDERPASS_CMD, "DS",
6990414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                        "Incorrectly binding compute pipeline (0x%" PRIxLEAST64 ") during active RenderPass (0x%" PRIxLEAST64 ")",
6991e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis                        (uint64_t)pipeline, (uint64_t)cb_state->activeRenderPass->renderPass);
69925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
69934527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton        // TODO: VALIDATION_ERROR_00594 VALIDATION_ERROR_00596
69945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6995e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        PIPELINE_STATE *pipe_state = getPipelineState(dev_data, pipeline);
6996e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        if (pipe_state) {
6997e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            cb_state->lastBound[pipelineBindPoint].pipeline_state = pipe_state;
6998e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            set_cb_pso_status(cb_state, pipe_state);
6999e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            set_pipeline_state(pipe_state);
70005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
7001e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
70024527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            (uint64_t)pipeline, __LINE__, VALIDATION_ERROR_00600, "DS",
70034527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            "Attempt to bind Pipeline 0x%" PRIxLEAST64 " that doesn't exist! %s", (uint64_t)(pipeline),
70044527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            validation_error_map[VALIDATION_ERROR_00600]);
7005e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        }
7006e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        addCommandBufferBinding(&pipe_state->cb_bindings,
7007e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis                                {reinterpret_cast<uint64_t &>(pipeline), VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT}, cb_state);
7008e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        if (VK_PIPELINE_BIND_POINT_GRAPHICS == pipelineBindPoint) {
7009e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            // Add binding for child renderpass
70109a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto rp_state = GetRenderPassState(dev_data, pipe_state->graphicsPipelineCI.renderPass);
7011e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            if (rp_state) {
7012e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis                addCommandBufferBinding(
7013e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis                    &rp_state->cb_bindings,
7014e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis                    {reinterpret_cast<uint64_t &>(rp_state->renderPass), VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT}, cb_state);
7015e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            }
70165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
70175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7018b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7019cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdBindPipeline(commandBuffer, pipelineBindPoint, pipeline);
70205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
70215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7022bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetViewport(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount,
7023bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                          const VkViewport *pViewports) {
702483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
702556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7026b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
70279a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
70285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
702929f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETVIEWPORTSTATE, "vkCmdSetViewport()");
70301ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETVIEWPORTSTATE);
7031bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pCB->viewportMask |= ((1u << viewportCount) - 1u) << firstViewport;
70325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7033b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7034cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetViewport(commandBuffer, firstViewport, viewportCount, pViewports);
70355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
70365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7037bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetScissor(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount,
7038bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         const VkRect2D *pScissors) {
703983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
704056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7041b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
70429a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
70435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
704429f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETSCISSORSTATE, "vkCmdSetScissor()");
70451ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETSCISSORSTATE);
7046bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pCB->scissorMask |= ((1u << scissorCount) - 1u) << firstScissor;
70475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7048b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7049cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetScissor(commandBuffer, firstScissor, scissorCount, pScissors);
70505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
70515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
705289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth) {
7053a27508babf63d50aea75883a3702979193c23683Mark Young    bool skip_call = false;
705456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7055b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
70569a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
70575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
705829f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETLINEWIDTHSTATE, "vkCmdSetLineWidth()");
70591ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETLINEWIDTHSTATE);
70605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_LINE_WIDTH_SET;
7061a27508babf63d50aea75883a3702979193c23683Mark Young
70624c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis        PIPELINE_STATE *pPipeTrav = pCB->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].pipeline_state;
7063a27508babf63d50aea75883a3702979193c23683Mark Young        if (pPipeTrav != NULL && !isDynamic(pPipeTrav, VK_DYNAMIC_STATE_LINE_WIDTH)) {
7064a27508babf63d50aea75883a3702979193c23683Mark Young            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0,
706555eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                 reinterpret_cast<uint64_t &>(commandBuffer), __LINE__, VALIDATION_ERROR_01476, "DS",
7066386d9a9a77f884789a7ae4c3890aecd47132f2babaldurk                                 "vkCmdSetLineWidth called but pipeline was created without VK_DYNAMIC_STATE_LINE_WIDTH "
706755eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                 "flag.  This is undefined behavior and could be ignored. %s",
706855eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                                 validation_error_map[VALIDATION_ERROR_01476]);
7069a27508babf63d50aea75883a3702979193c23683Mark Young        } else {
7070a27508babf63d50aea75883a3702979193c23683Mark Young            skip_call |= verifyLineWidth(dev_data, DRAWSTATE_INVALID_SET, reinterpret_cast<uint64_t &>(commandBuffer), lineWidth);
7071a27508babf63d50aea75883a3702979193c23683Mark Young        }
70725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7073b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7074cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetLineWidth(commandBuffer, lineWidth);
70755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
70765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7077bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetDepthBias(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp,
7078bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           float depthBiasSlopeFactor) {
707983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
708056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7081b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
70829a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
70835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
708429f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETDEPTHBIASSTATE, "vkCmdSetDepthBias()");
70851ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETDEPTHBIASSTATE);
70865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_DEPTH_BIAS_SET;
70875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7088b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
708983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (!skip_call)
70904a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdSetDepthBias(commandBuffer, depthBiasConstantFactor, depthBiasClamp, depthBiasSlopeFactor);
70915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
70925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
709389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdSetBlendConstants(VkCommandBuffer commandBuffer, const float blendConstants[4]) {
709483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
709556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7096b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
70979a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
70985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
709929f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETBLENDSTATE, "vkCmdSetBlendConstants()");
71001ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETBLENDSTATE);
71013d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        pCB->status |= CBSTATUS_BLEND_CONSTANTS_SET;
71025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7103b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7104cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetBlendConstants(commandBuffer, blendConstants);
71055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
71065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7107bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetDepthBounds(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds) {
710883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
710956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7110b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
71119a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
71125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
711329f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETDEPTHBOUNDSSTATE, "vkCmdSetDepthBounds()");
71141ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETDEPTHBOUNDSSTATE);
71155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_DEPTH_BOUNDS_SET;
71165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7117b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7118cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetDepthBounds(commandBuffer, minDepthBounds, maxDepthBounds);
71195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
71205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7121bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetStencilCompareMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask,
7122bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                    uint32_t compareMask) {
712383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
712456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7125b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
71269a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
71275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
712829f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETSTENCILREADMASKSTATE, "vkCmdSetStencilCompareMask()");
71291ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETSTENCILREADMASKSTATE);
71305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_STENCIL_READ_MASK_SET;
71315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7132b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7133cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetStencilCompareMask(commandBuffer, faceMask, compareMask);
71345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
71355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7136bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetStencilWriteMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask) {
713783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
713856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7139b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
71409a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
71415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
714229f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETSTENCILWRITEMASKSTATE, "vkCmdSetStencilWriteMask()");
71431ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETSTENCILWRITEMASKSTATE);
71445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_STENCIL_WRITE_MASK_SET;
71455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7146b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7147cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetStencilWriteMask(commandBuffer, faceMask, writeMask);
71485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
71495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7150bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetStencilReference(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference) {
715183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
715256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7153b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
71549a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
71555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
715629f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETSTENCILREFERENCESTATE, "vkCmdSetStencilReference()");
71571ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETSTENCILREFERENCESTATE);
71585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_STENCIL_REFERENCE_SET;
71595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7160b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7161cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetStencilReference(commandBuffer, faceMask, reference);
71625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
71635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7164bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBindDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
7165bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 VkPipelineLayout layout, uint32_t firstSet, uint32_t setCount,
7166bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkDescriptorSet *pDescriptorSets, uint32_t dynamicOffsetCount,
7167bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const uint32_t *pDynamicOffsets) {
7168946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
716956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7170b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7171946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
7172946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (cb_state) {
7173946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_state, CMD_BINDDESCRIPTORSETS, "vkCmdBindDescriptorSets()");
7174ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        // Track total count of dynamic descriptor types to make sure we have an offset for each one
7175946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        uint32_t total_dynamic_descriptors = 0;
7176946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        string error_string = "";
7177946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        uint32_t last_set_index = firstSet + setCount - 1;
7178946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        if (last_set_index >= cb_state->lastBound[pipelineBindPoint].boundDescriptorSets.size()) {
7179946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            cb_state->lastBound[pipelineBindPoint].boundDescriptorSets.resize(last_set_index + 1);
7180946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            cb_state->lastBound[pipelineBindPoint].dynamicOffsets.resize(last_set_index + 1);
7181946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        }
7182946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        auto old_final_bound_set = cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[last_set_index];
7183ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        auto pipeline_layout = getPipelineLayout(dev_data, layout);
7184ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        for (uint32_t set_idx = 0; set_idx < setCount; set_idx++) {
7185ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            cvdescriptorset::DescriptorSet *descriptor_set = GetSetNode(dev_data, pDescriptorSets[set_idx]);
7186ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            if (descriptor_set) {
7187946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                cb_state->lastBound[pipelineBindPoint].pipeline_layout = *pipeline_layout;
7188946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[set_idx + firstSet] = descriptor_set;
7189946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT,
7190946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[set_idx], __LINE__,
7191946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                DRAWSTATE_NONE, "DS", "Descriptor Set 0x%" PRIxLEAST64 " bound on pipeline %s",
7192946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                (uint64_t)pDescriptorSets[set_idx], string_VkPipelineBindPoint(pipelineBindPoint));
7193ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                if (!descriptor_set->IsUpdated() && (descriptor_set->GetTotalDescriptorCount() != 0)) {
7194946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
7195946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[set_idx], __LINE__,
7196946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS",
7197946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    "Descriptor Set 0x%" PRIxLEAST64
7198946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    " bound but it was never updated. You may want to either update it or not bind it.",
7199946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    (uint64_t)pDescriptorSets[set_idx]);
7200ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                }
7201ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                // Verify that set being bound is compatible with overlapping setLayout of pipelineLayout
7202946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                if (!verify_set_layout_compatibility(dev_data, descriptor_set, pipeline_layout, set_idx + firstSet, error_string)) {
7203946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
7204946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[set_idx], __LINE__,
7205946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    VALIDATION_ERROR_00974, "DS",
7206946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    "descriptorSet #%u being bound is not compatible with overlapping descriptorSetLayout "
7207946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    "at index %u of pipelineLayout 0x%" PRIxLEAST64 " due to: %s. %s",
7208946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    set_idx, set_idx + firstSet, reinterpret_cast<uint64_t &>(layout), error_string.c_str(),
7209946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    validation_error_map[VALIDATION_ERROR_00974]);
72105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
7211ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski
7212946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                auto set_dynamic_descriptor_count = descriptor_set->GetDynamicDescriptorCount();
7213ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski
7214946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                cb_state->lastBound[pipelineBindPoint].dynamicOffsets[firstSet + set_idx].clear();
7215ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski
7216946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                if (set_dynamic_descriptor_count) {
7217ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                    // First make sure we won't overstep bounds of pDynamicOffsets array
7218946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    if ((total_dynamic_descriptors + set_dynamic_descriptor_count) > dynamicOffsetCount) {
7219946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
7220946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                        VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[set_idx],
7221946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                        __LINE__, DRAWSTATE_INVALID_DYNAMIC_OFFSET_COUNT, "DS",
7222946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                        "descriptorSet #%u (0x%" PRIxLEAST64
7223946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                        ") requires %u dynamicOffsets, but only %u dynamicOffsets are left in pDynamicOffsets "
7224946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                        "array. There must be one dynamic offset for each dynamic descriptor being bound.",
7225946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                        set_idx, (uint64_t)pDescriptorSets[set_idx], descriptor_set->GetDynamicDescriptorCount(),
7226946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                        (dynamicOffsetCount - total_dynamic_descriptors));
7227ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                    } else {  // Validate and store dynamic offsets with the set
7228ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                        // Validate Dynamic Offset Minimums
7229946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        uint32_t cur_dyn_offset = total_dynamic_descriptors;
7230ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                        for (uint32_t d = 0; d < descriptor_set->GetTotalDescriptorCount(); d++) {
7231ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            if (descriptor_set->GetTypeFromGlobalIndex(d) == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) {
7232ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                if (vk_safe_modulo(
7233ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        pDynamicOffsets[cur_dyn_offset],
7234ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment) != 0) {
7235946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    skip |= log_msg(
7236ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
7237ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, VALIDATION_ERROR_00978, "DS",
7238ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        "vkCmdBindDescriptorSets(): pDynamicOffsets[%d] is %d but must be a multiple of "
7239ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        "device limit minUniformBufferOffsetAlignment 0x%" PRIxLEAST64 ". %s",
7240ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        cur_dyn_offset, pDynamicOffsets[cur_dyn_offset],
7241ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment,
7242ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        validation_error_map[VALIDATION_ERROR_00978]);
7243ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                }
7244ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                cur_dyn_offset++;
7245ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            } else if (descriptor_set->GetTypeFromGlobalIndex(d) == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
7246ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                if (vk_safe_modulo(
7247ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        pDynamicOffsets[cur_dyn_offset],
7248ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        dev_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment) != 0) {
7249946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    skip |= log_msg(
7250ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
7251ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, VALIDATION_ERROR_00978, "DS",
7252ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        "vkCmdBindDescriptorSets(): pDynamicOffsets[%d] is %d but must be a multiple of "
7253ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        "device limit minStorageBufferOffsetAlignment 0x%" PRIxLEAST64 ". %s",
7254ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        cur_dyn_offset, pDynamicOffsets[cur_dyn_offset],
7255ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        dev_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment,
7256ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        validation_error_map[VALIDATION_ERROR_00978]);
7257ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                }
7258ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                cur_dyn_offset++;
7259ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            }
726072d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                        }
7261ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski
7262946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        cb_state->lastBound[pipelineBindPoint].dynamicOffsets[firstSet + set_idx] =
7263946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            std::vector<uint32_t>(pDynamicOffsets + total_dynamic_descriptors,
7264946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                                  pDynamicOffsets + total_dynamic_descriptors + set_dynamic_descriptor_count);
7265ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                        // Keep running total of dynamic descriptor count to verify at the end
7266946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        total_dynamic_descriptors += set_dynamic_descriptor_count;
726772d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                    }
726872d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                }
7269ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            } else {
7270946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                skip |= log_msg(
7271ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
7272ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                    (uint64_t)pDescriptorSets[set_idx], __LINE__, DRAWSTATE_INVALID_SET, "DS",
7273ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                    "Attempt to bind descriptor set 0x%" PRIxLEAST64 " that doesn't exist!", (uint64_t)pDescriptorSets[set_idx]);
7274ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            }
7275946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            UpdateCmdBufferLastCmd(cb_state, CMD_BINDDESCRIPTORSETS);
7276ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            // For any previously bound sets, need to set them to "invalid" if they were disturbed by this update
7277ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            if (firstSet > 0) {  // Check set #s below the first bound set
7278ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                for (uint32_t i = 0; i < firstSet; ++i) {
7279946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    if (cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[i] &&
7280946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        !verify_set_layout_compatibility(dev_data, cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[i],
7281946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                                         pipeline_layout, i, error_string)) {
7282946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        skip |= log_msg(
7283ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
7284ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
7285946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            (uint64_t)cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[i], __LINE__, DRAWSTATE_NONE, "DS",
7286ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            "DescriptorSet 0x%" PRIxLEAST64
7287ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            " previously bound as set #%u was disturbed by newly bound pipelineLayout (0x%" PRIxLEAST64 ")",
7288946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            (uint64_t)cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[i], i, (uint64_t)layout);
7289946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[i] = VK_NULL_HANDLE;
72905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
72915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
72925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
7293ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            // Check if newly last bound set invalidates any remaining bound sets
7294946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            if ((cb_state->lastBound[pipelineBindPoint].boundDescriptorSets.size() - 1) > (last_set_index)) {
7295946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                if (old_final_bound_set &&
7296946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    !verify_set_layout_compatibility(dev_data, old_final_bound_set, pipeline_layout, last_set_index,
7297946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                                     error_string)) {
7298946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    auto old_set = old_final_bound_set->GetSet();
7299946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
7300946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, reinterpret_cast<uint64_t &>(old_set), __LINE__,
7301946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    DRAWSTATE_NONE, "DS", "DescriptorSet 0x%" PRIxLEAST64
7302946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                                          " previously bound as set #%u is incompatible with set 0x%" PRIxLEAST64
7303946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                                          " newly bound as set #%u so set #%u and any subsequent sets were "
7304946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                                          "disturbed by newly bound pipelineLayout (0x%" PRIxLEAST64 ")",
7305946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    reinterpret_cast<uint64_t &>(old_set), last_set_index,
7306946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    (uint64_t)cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[last_set_index],
7307946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    last_set_index, last_set_index + 1, (uint64_t)layout);
7308946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    cb_state->lastBound[pipelineBindPoint].boundDescriptorSets.resize(last_set_index + 1);
7309ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                }
7310787f29d93dee194c015789cf61c079504c980572Tobin Ehlis            }
7311ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        }
7312ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        //  dynamicOffsetCount must equal the total number of dynamic descriptors in the sets being bound
7313946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        if (total_dynamic_descriptors != dynamicOffsetCount) {
7314946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
7315946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            (uint64_t)commandBuffer, __LINE__, VALIDATION_ERROR_00975, "DS",
7316946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            "Attempting to bind %u descriptorSets with %u dynamic descriptors, but dynamicOffsetCount "
7317946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            "is %u. It should exactly match the number of dynamic descriptors. %s",
7318946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            setCount, total_dynamic_descriptors, dynamicOffsetCount, validation_error_map[VALIDATION_ERROR_00975]);
73195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
73205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7321b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7322946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip)
73234a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdBindDescriptorSets(commandBuffer, pipelineBindPoint, layout, firstSet, setCount,
73244a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                       pDescriptorSets, dynamicOffsetCount, pDynamicOffsets);
73255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
73265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7327bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBindIndexBuffer(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
7328bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              VkIndexType indexType) {
7329946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
733056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7331593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis    // TODO : Somewhere need to verify that IBs have correct usage state flagged
7332b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7333b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski
73349a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto buffer_state = GetBufferState(dev_data, buffer);
73359a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
73365cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (cb_node && buffer_state) {
7337946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_node, CMD_BINDINDEXBUFFER, "vkCmdBindIndexBuffer()");
7338946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateMemoryIsBoundToBuffer(dev_data, buffer_state, "vkCmdBindIndexBuffer()", VALIDATION_ERROR_02543);
7339ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        std::function<bool()> function = [=]() {
7340ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            return ValidateBufferMemoryIsValid(dev_data, buffer_state, "vkCmdBindIndexBuffer()");
7341ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        };
7342ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        cb_node->validate_functions.push_back(function);
7343ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        UpdateCmdBufferLastCmd(cb_node, CMD_BINDINDEXBUFFER);
7344ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        VkDeviceSize offset_align = 0;
7345ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        switch (indexType) {
7346ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            case VK_INDEX_TYPE_UINT16:
7347ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                offset_align = 2;
7348ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                break;
7349ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            case VK_INDEX_TYPE_UINT32:
7350ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                offset_align = 4;
7351ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                break;
7352ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            default:
7353ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                // ParamChecker should catch bad enum, we'll also throw alignment error below if offset_align stays 0
7354ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                break;
73555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7356ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        if (!offset_align || (offset % offset_align)) {
7357946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
7358946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            DRAWSTATE_VTX_INDEX_ALIGNMENT_ERROR, "DS",
7359946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            "vkCmdBindIndexBuffer() offset (0x%" PRIxLEAST64 ") does not fall on alignment (%s) boundary.", offset,
7360946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            string_VkIndexType(indexType));
7361ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        }
7362ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        cb_node->status |= CBSTATUS_INDEX_BUFFER_BOUND;
7363ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
7364ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
73655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7366b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7367946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdBindIndexBuffer(commandBuffer, buffer, offset, indexType);
73685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
73695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
73705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisvoid updateResourceTracking(GLOBAL_CB_NODE *pCB, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer *pBuffers) {
73715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t end = firstBinding + bindingCount;
73725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB->currentDrawData.buffers.size() < end) {
73735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->currentDrawData.buffers.resize(end);
73745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
73755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < bindingCount; ++i) {
73765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->currentDrawData.buffers[i + firstBinding] = pBuffers[i];
73775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
73785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
73795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7380e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic inline void updateResourceTrackingOnDraw(GLOBAL_CB_NODE *pCB) { pCB->drawData.push_back(pCB->currentDrawData); }
73815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7382bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBindVertexBuffers(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount,
7383bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkBuffer *pBuffers, const VkDeviceSize *pOffsets) {
7384946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
738556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7386593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis    // TODO : Somewhere need to verify that VBs have correct usage state flagged
7387b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7388b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski
73899a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
73909f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis    if (cb_node) {
7391946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_node, CMD_BINDVERTEXBUFFER, "vkCmdBindVertexBuffer()");
7392ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        for (uint32_t i = 0; i < bindingCount; ++i) {
7393ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            auto buffer_state = GetBufferState(dev_data, pBuffers[i]);
7394ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            assert(buffer_state);
7395946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            skip |= ValidateMemoryIsBoundToBuffer(dev_data, buffer_state, "vkCmdBindVertexBuffers()", VALIDATION_ERROR_02546);
7396ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            std::function<bool()> function = [=]() {
7397ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                return ValidateBufferMemoryIsValid(dev_data, buffer_state, "vkCmdBindVertexBuffers()");
7398ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            };
7399ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            cb_node->validate_functions.push_back(function);
74005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7401ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        UpdateCmdBufferLastCmd(cb_node, CMD_BINDVERTEXBUFFER);
7402ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        updateResourceTracking(cb_node, firstBinding, bindingCount, pBuffers);
74035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
74047828015969ab31ee01d597f0288cbb124b637fcdMark Lobodzinski        assert(0);
74055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7406b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7407946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdBindVertexBuffers(commandBuffer, firstBinding, bindingCount, pBuffers, pOffsets);
74085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
74095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
741025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// Expects global_lock to be held by caller
74115569d6457ac22e7d245f3cdee045e71ffbc8b06eTobin Ehlisstatic void MarkStoreImagesAndBuffersAsWritten(layer_data *dev_data, GLOBAL_CB_NODE *pCB) {
74127a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis    for (auto imageView : pCB->updateImages) {
74139a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto view_state = GetImageViewState(dev_data, imageView);
7414cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!view_state) continue;
7415249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis
74169a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto image_state = GetImageState(dev_data, view_state->create_info.image);
74171facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        assert(image_state);
7418e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
74191facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            SetImageMemoryValid(dev_data, image_state, true);
7420e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
74217a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        };
74227a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        pCB->validate_functions.push_back(function);
74237a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis    }
74247a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis    for (auto buffer : pCB->updateBuffers) {
74259a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto buffer_state = GetBufferState(dev_data, buffer);
74265cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        assert(buffer_state);
7427e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
74285cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            SetBufferMemoryValid(dev_data, buffer_state, true);
7429e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
74307a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        };
74317a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        pCB->validate_functions.push_back(function);
74325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
74335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
74345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7435ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis// Generic function to handle validation for all CmdDraw* type functions
7436ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool ValidateCmdDrawType(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed, VkPipelineBindPoint bind_point,
7437ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                CMD_TYPE cmd_type, GLOBAL_CB_NODE **cb_state, const char *caller,
74384f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                UNIQUE_VALIDATION_ERROR_CODE msg_code, UNIQUE_VALIDATION_ERROR_CODE const dynamic_state_msg_code) {
743958b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    bool skip = false;
74409a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *cb_state = GetCBNode(dev_data, cmd_buffer);
744158b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    if (*cb_state) {
7442ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis        skip |= ValidateCmd(dev_data, *cb_state, cmd_type, caller);
74434f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes        skip |= ValidateDrawState(dev_data, *cb_state, indexed, bind_point, caller, dynamic_state_msg_code);
744425d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis        skip |= (VK_PIPELINE_BIND_POINT_GRAPHICS == bind_point) ? outsideRenderPass(dev_data, *cb_state, caller, msg_code)
744525d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis                                                                : insideRenderPass(dev_data, *cb_state, caller, msg_code);
744658b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    }
744758b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    return skip;
744858b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis}
744958b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis
745025d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis// Generic function to handle state update for all CmdDraw* and CmdDispatch* type functions
7451ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void UpdateStateCmdDrawDispatchType(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
7452ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                           CMD_TYPE cmd_type) {
7453ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateDrawState(dev_data, cb_state, bind_point);
74542f921d33544c162dcb726fc3c7b915e89c02ff24Tobin Ehlis    MarkStoreImagesAndBuffersAsWritten(dev_data, cb_state);
74551ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis    UpdateCmdBufferLastCmd(cb_state, cmd_type);
745625d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis}
745725d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis
7458ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis// Generic function to handle state update for all CmdDraw* type functions
7459ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void UpdateStateCmdDrawType(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
7460ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                   CMD_TYPE cmd_type, DRAW_TYPE draw_type) {
7461ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawDispatchType(dev_data, cb_state, bind_point, cmd_type);
7462c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis    updateResourceTrackingOnDraw(cb_state);
7463ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    cb_state->drawCount[draw_type]++;
7464ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis}
7465ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis
7466ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDraw(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed, VkPipelineBindPoint bind_point,
7467ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                   GLOBAL_CB_NODE **cb_state, const char *caller) {
74684f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes    return ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAW, cb_state, caller, VALIDATION_ERROR_01365,
74694f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                               VALIDATION_ERROR_02203);
7470ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis}
7471ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis
7472ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDraw(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point) {
7473ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawType(dev_data, cb_state, bind_point, CMD_DRAW, DRAW);
7474c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis}
7475c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis
747689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount,
747789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                   uint32_t firstVertex, uint32_t firstInstance) {
747856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
747958b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
7480b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7481ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    bool skip = PreCallValidateCmdDraw(dev_data, commandBuffer, false, VK_PIPELINE_BIND_POINT_GRAPHICS, &cb_state, "vkCmdDraw()");
7482b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
748358b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    if (!skip) {
74844a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDraw(commandBuffer, vertexCount, instanceCount, firstVertex, firstInstance);
7485c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis        lock.lock();
7486ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDraw(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS);
7487c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis        lock.unlock();
7488c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis    }
74895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
74905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7491ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDrawIndexed(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed,
7492ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                          VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state, const char *caller) {
74934f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes    return ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAWINDEXED, cb_state, caller, VALIDATION_ERROR_01372,
74944f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                               VALIDATION_ERROR_02216);
7495ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis}
7496ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis
7497ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDrawIndexed(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point) {
7498ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawType(dev_data, cb_state, bind_point, CMD_DRAWINDEXED, DRAW_INDEXED);
7499ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis}
7500ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis
7501bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount,
7502bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                          uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance) {
750356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7504ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
7505b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7506ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    bool skip = PreCallValidateCmdDrawIndexed(dev_data, commandBuffer, true, VK_PIPELINE_BIND_POINT_GRAPHICS, &cb_state,
7507ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                              "vkCmdDrawIndexed()");
7508b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7509ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    if (!skip) {
75104a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDrawIndexed(commandBuffer, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
7511ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis        lock.lock();
7512ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDrawIndexed(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS);
7513ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis        lock.unlock();
7514ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    }
75155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
75165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7517ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDrawIndirect(layer_data *dev_data, VkCommandBuffer cmd_buffer, VkBuffer buffer, bool indexed,
7518ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                           VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state, BUFFER_STATE **buffer_state,
7519ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                           const char *caller) {
75204f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes    bool skip = ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAWINDIRECT, cb_state, caller,
75214f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                    VALIDATION_ERROR_01381, VALIDATION_ERROR_02234);
75229a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *buffer_state = GetBufferState(dev_data, buffer);
752335ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis    skip |= ValidateMemoryIsBoundToBuffer(dev_data, *buffer_state, caller, VALIDATION_ERROR_02544);
7524d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    return skip;
7525d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis}
7526d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis
7527ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDrawIndirect(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
7528ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                          BUFFER_STATE *buffer_state) {
7529ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawType(dev_data, cb_state, bind_point, CMD_DRAWINDIRECT, DRAW_INDIRECT);
7530d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    AddCommandBufferBindingBuffer(dev_data, cb_state, buffer_state);
7531d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis}
7532d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis
7533bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count,
7534bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           uint32_t stride) {
753556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7536d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
7537d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    BUFFER_STATE *buffer_state = nullptr;
7538b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7539872a2f0ca3ffdeddfa7483e777191fa64b853892Tony Barbour    bool skip = PreCallValidateCmdDrawIndirect(dev_data, commandBuffer, buffer, false, VK_PIPELINE_BIND_POINT_GRAPHICS, &cb_state,
7540ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                               &buffer_state, "vkCmdDrawIndirect()");
7541b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7542d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    if (!skip) {
75434a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDrawIndirect(commandBuffer, buffer, offset, count, stride);
7544d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis        lock.lock();
7545ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDrawIndirect(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, buffer_state);
7546d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis        lock.unlock();
7547d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    }
75485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
75495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7550ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDrawIndexedIndirect(layer_data *dev_data, VkCommandBuffer cmd_buffer, VkBuffer buffer, bool indexed,
7551ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                  VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state,
7552ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                  BUFFER_STATE **buffer_state, const char *caller) {
7553ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    bool skip = ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAWINDEXEDINDIRECT, cb_state, caller,
75544f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                    VALIDATION_ERROR_01393, VALIDATION_ERROR_02272);
75559a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *buffer_state = GetBufferState(dev_data, buffer);
755635ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis    skip |= ValidateMemoryIsBoundToBuffer(dev_data, *buffer_state, caller, VALIDATION_ERROR_02545);
75570c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    return skip;
75580c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis}
75590c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis
7560ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDrawIndexedIndirect(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
7561ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                 BUFFER_STATE *buffer_state) {
7562ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawType(dev_data, cb_state, bind_point, CMD_DRAWINDEXEDINDIRECT, DRAW_INDEXED_INDIRECT);
75630c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    AddCommandBufferBindingBuffer(dev_data, cb_state, buffer_state);
75640c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis}
75650c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis
7566bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
7567bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                  uint32_t count, uint32_t stride) {
756856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
75690c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
75700c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    BUFFER_STATE *buffer_state = nullptr;
7571b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
75720c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    bool skip = PreCallValidateCmdDrawIndexedIndirect(dev_data, commandBuffer, buffer, true, VK_PIPELINE_BIND_POINT_GRAPHICS,
7573ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                      &cb_state, &buffer_state, "vkCmdDrawIndexedIndirect()");
7574b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
75750c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    if (!skip) {
75764a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDrawIndexedIndirect(commandBuffer, buffer, offset, count, stride);
75770c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis        lock.lock();
7578ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDrawIndexedIndirect(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, buffer_state);
75790c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis        lock.unlock();
75800c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    }
75815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
75825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7583ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDispatch(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed,
7584ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                       VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state, const char *caller) {
75854f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes    return ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DISPATCH, cb_state, caller, VALIDATION_ERROR_01562,
75864f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                               VALIDATION_ERROR_UNDEFINED);
758725d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis}
758825d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis
7589ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDispatch(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point) {
7590ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawDispatchType(dev_data, cb_state, bind_point, CMD_DISPATCH);
759125d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis}
759225d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis
759389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z) {
759456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
759525d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
7596b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7597ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    bool skip =
7598ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PreCallValidateCmdDispatch(dev_data, commandBuffer, false, VK_PIPELINE_BIND_POINT_COMPUTE, &cb_state, "vkCmdDispatch()");
7599b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
760025d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis    if (!skip) {
76014a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDispatch(commandBuffer, x, y, z);
760225d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis        lock.lock();
7603ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDispatch(dev_data, cb_state, VK_PIPELINE_BIND_POINT_COMPUTE);
760425d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis        lock.unlock();
760525d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis    }
76065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
76075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7608ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDispatchIndirect(layer_data *dev_data, VkCommandBuffer cmd_buffer, VkBuffer buffer, bool indexed,
7609ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                               VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state,
7610ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                               BUFFER_STATE **buffer_state, const char *caller) {
7611ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    bool skip = ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DISPATCHINDIRECT, cb_state, caller,
76124f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                    VALIDATION_ERROR_01569, VALIDATION_ERROR_UNDEFINED);
76139a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *buffer_state = GetBufferState(dev_data, buffer);
761435ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis    skip |= ValidateMemoryIsBoundToBuffer(dev_data, *buffer_state, caller, VALIDATION_ERROR_02547);
761579c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    return skip;
761679c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis}
761779c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis
7618ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDispatchIndirect(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
7619ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                              BUFFER_STATE *buffer_state) {
7620ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawDispatchType(dev_data, cb_state, bind_point, CMD_DISPATCHINDIRECT);
762179c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    AddCommandBufferBindingBuffer(dev_data, cb_state, buffer_state);
762279c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis}
762379c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis
7624bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset) {
762556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
762679c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
762779c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    BUFFER_STATE *buffer_state = nullptr;
7628b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
76297433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis    bool skip = PreCallValidateCmdDispatchIndirect(dev_data, commandBuffer, buffer, false, VK_PIPELINE_BIND_POINT_COMPUTE,
7630ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                   &cb_state, &buffer_state, "vkCmdDispatchIndirect()");
7631b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
763279c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    if (!skip) {
76334a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDispatchIndirect(commandBuffer, buffer, offset);
763479c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis        lock.lock();
7635ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDispatchIndirect(dev_data, cb_state, VK_PIPELINE_BIND_POINT_COMPUTE, buffer_state);
763679c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis        lock.unlock();
763779c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    }
76385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
76395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
764089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
764189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                         uint32_t regionCount, const VkBufferCopy *pRegions) {
7642c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7643b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7644ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
7645c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski    auto cb_node = GetCBNode(device_data, commandBuffer);
7646c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski    auto src_buffer_state = GetBufferState(device_data, srcBuffer);
7647c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski    auto dst_buffer_state = GetBufferState(device_data, dstBuffer);
7648593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
7649c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski    if (cb_node && src_buffer_state && dst_buffer_state) {
7650c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski        bool skip = PreCallValidateCmdCopyBuffer(device_data, cb_node, src_buffer_state, dst_buffer_state);
7651c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski        if (!skip) {
7652c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski            PreCallRecordCmdCopyBuffer(device_data, cb_node, src_buffer_state, dst_buffer_state);
7653c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski            lock.unlock();
7654c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski            device_data->dispatch_table.CmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, regionCount, pRegions);
7655c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski        }
7656ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
7657c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski        lock.unlock();
7658ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
76595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
76605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
76615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7662bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
7663bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
7664bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        const VkImageCopy *pRegions) {
76656a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    bool skip = false;
76666a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7667b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7668249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis
76696a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    auto cb_node = GetCBNode(device_data, commandBuffer);
76706a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    auto src_image_state = GetImageState(device_data, srcImage);
76716a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    auto dst_image_state = GetImageState(device_data, dstImage);
76721facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (cb_node && src_image_state && dst_image_state) {
76736a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski        skip = PreCallValidateCmdCopyImage(device_data, cb_node, src_image_state, dst_image_state, regionCount, pRegions,
76746a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski                                           srcImageLayout, dstImageLayout);
76756a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski        if (!skip) {
76766a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski            PreCallRecordCmdCopyImage(device_data, cb_node, src_image_state, dst_image_state);
76776a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski            lock.unlock();
76786a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski            device_data->dispatch_table.CmdCopyImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
76796a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski                                                     pRegions);
76805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7681249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis    } else {
76826a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski        lock.unlock();
7683249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis        assert(0);
76845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
76855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
76865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7687eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski// Validate that an image's sampleCount matches the requirement for a specific API call
768860568995aca225f81acda8ce40cfabbea2c19397Mark Lobodzinskibool ValidateImageSampleCount(layer_data *dev_data, IMAGE_STATE *image_state, VkSampleCountFlagBits sample_count,
768960568995aca225f81acda8ce40cfabbea2c19397Mark Lobodzinski                              const char *location, UNIQUE_VALIDATION_ERROR_CODE msgCode) {
7690eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski    bool skip = false;
76911facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (image_state->createInfo.samples != sample_count) {
769255eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen        skip =
769355eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
769455eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                    reinterpret_cast<uint64_t &>(image_state->image), 0, msgCode, "DS",
769555eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                    "%s for image 0x%" PRIxLEAST64 " was created with a sample count of %s but must be %s. %s", location,
769655eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                    reinterpret_cast<uint64_t &>(image_state->image), string_VkSampleCountFlagBits(image_state->createInfo.samples),
769755eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                    string_VkSampleCountFlagBits(sample_count), validation_error_map[msgCode]);
7698eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski    }
7699eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski    return skip;
7700eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski}
7701eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski
7702bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
7703bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
7704bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        const VkImageBlit *pRegions, VkFilter filter) {
770556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7706b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7707593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
77089a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
77099a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto src_image_state = GetImageState(dev_data, srcImage);
77109a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto dst_image_state = GetImageState(dev_data, dstImage);
77110dc51740dbd7b9f0ba7c071e0bf96f63d6d48c85Mark Lobodzinski
7712055112ec99304db71d55b69a60e1da14e8af8f60Mark Lobodzinski    bool skip = PreCallValidateCmdBlitImage(dev_data, cb_node, src_image_state, dst_image_state, regionCount, pRegions, filter);
77130dc51740dbd7b9f0ba7c071e0bf96f63d6d48c85Mark Lobodzinski
7714dca02371c9531e7a9a2a51decae1db4d297862c4Mark Lobodzinski    if (!skip) {
7715eebd811afd800663f15fda8fc71bc203a03fe294Mark Lobodzinski        PreCallRecordCmdBlitImage(dev_data, cb_node, src_image_state, dst_image_state);
7716eebd811afd800663f15fda8fc71bc203a03fe294Mark Lobodzinski        lock.unlock();
77174a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdBlitImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
77184a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                              pRegions, filter);
77190dc51740dbd7b9f0ba7c071e0bf96f63d6d48c85Mark Lobodzinski    }
77205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
77215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7722bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage,
7723bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                VkImageLayout dstImageLayout, uint32_t regionCount,
7724bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkBufferImageCopy *pRegions) {
7725940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7726b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7727940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    bool skip = false;
7728940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto cb_node = GetCBNode(device_data, commandBuffer);
7729940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto src_buffer_state = GetBufferState(device_data, srcBuffer);
7730940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto dst_image_state = GetImageState(device_data, dstImage);
7731940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    if (cb_node && src_buffer_state && dst_image_state) {
7732940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski        skip = PreCallValidateCmdCopyBufferToImage(device_data, dstImageLayout, cb_node, src_buffer_state, dst_image_state,
773371c68ce753146a69508694cfc5fc2dcfa08c692eMark Lobodzinski                                                        regionCount, pRegions, "vkCmdCopyBufferToImage()");
7734ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
7735d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski        lock.unlock();
7736ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
7737e4d82c37d6c861b388dbc80297c18d6255858cb4Dave Houlton        // TODO: report VU01244 here, or put in object tracker?
77385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7739940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    if (!skip) {
7740940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski        PreCallRecordCmdCopyBufferToImage(device_data, cb_node, src_buffer_state, dst_image_state);
7741d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski        lock.unlock();
7742940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski        device_data->dispatch_table.CmdCopyBufferToImage(commandBuffer, srcBuffer, dstImage, dstImageLayout, regionCount, pRegions);
7743d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski    }
77445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
77455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7746bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
7747bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy *pRegions) {
7748940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    bool skip = false;
7749940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7750b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7751593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
7752940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto cb_node = GetCBNode(device_data, commandBuffer);
7753940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto src_image_state = GetImageState(device_data, srcImage);
7754940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto dst_buffer_state = GetBufferState(device_data, dstBuffer);
7755940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    if (cb_node && src_image_state && dst_buffer_state) {
7756940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski        skip = PreCallValidateCmdCopyImageToBuffer(device_data, srcImageLayout, cb_node, src_image_state, dst_buffer_state,
775771c68ce753146a69508694cfc5fc2dcfa08c692eMark Lobodzinski                                                        regionCount, pRegions, "vkCmdCopyImageToBuffer()");
7758ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
7759d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski        lock.unlock();
7760ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
7761e4d82c37d6c861b388dbc80297c18d6255858cb4Dave Houlton        // TODO: report VU01262 here, or put in object tracker?
77625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7763940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    if (!skip) {
7764940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski        PreCallRecordCmdCopyImageToBuffer(device_data, cb_node, src_image_state, dst_buffer_state);
7765d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski        lock.unlock();
7766940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski        device_data->dispatch_table.CmdCopyImageToBuffer(commandBuffer, srcImage, srcImageLayout, dstBuffer, regionCount, pRegions);
7767d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski    }
77685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
77695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7770bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
7771bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           VkDeviceSize dataSize, const uint32_t *pData) {
777283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
777356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7774b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7775593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
77769a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
77779a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto dst_buff_state = GetBufferState(dev_data, dstBuffer);
77785cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (cb_node && dst_buff_state) {
777935ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis        skip_call |= ValidateMemoryIsBoundToBuffer(dev_data, dst_buff_state, "vkCmdUpdateBuffer()", VALIDATION_ERROR_02530);
7780ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Update bindings between buffer and cmd buffer
77815cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        AddCommandBufferBindingBuffer(dev_data, cb_node, dst_buff_state);
7782ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Validate that DST buffer has correct usage flags set
77835cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        skip_call |= ValidateBufferUsageFlags(dev_data, dst_buff_state, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true,
77841b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes                                              VALIDATION_ERROR_01146, "vkCmdUpdateBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
7785e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
77865cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            SetBufferMemoryValid(dev_data, dst_buff_state, true);
7787e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
77885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        };
77899f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
7790593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
779129f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, cb_node, CMD_UPDATEBUFFER, "vkCmdUpdateBuffer()");
77921ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(cb_node, CMD_UPDATEBUFFER);
7793ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen        skip_call |= insideRenderPass(dev_data, cb_node, "vkCmdUpdateBuffer()", VALIDATION_ERROR_01155);
7794ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
7795ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
77965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7797b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7798cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdUpdateBuffer(commandBuffer, dstBuffer, dstOffset, dataSize, pData);
77995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
78005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7801bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
7802bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         VkDeviceSize size, uint32_t data) {
780323bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7804b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
780523bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski    auto cb_node = GetCBNode(device_data, commandBuffer);
780623bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski    auto buffer_state = GetBufferState(device_data, dstBuffer);
7807593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
780823bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski    if (cb_node && buffer_state) {
780923bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski        bool skip = PreCallValidateCmdFillBuffer(device_data, cb_node, buffer_state);
781023bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski        if (!skip) {
781123bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski            PreCallRecordCmdFillBuffer(device_data, cb_node, buffer_state);
781223bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski            lock.unlock();
781323bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski            device_data->dispatch_table.CmdFillBuffer(commandBuffer, dstBuffer, dstOffset, size, data);
781423bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski        }
7815ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
781623bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski        lock.unlock();
7817ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
78185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
78195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
78205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
78214028af23e688ab5730f48ab2244dd042e2eefaedMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount,
78224028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski                                               const VkClearAttachment *pAttachments, uint32_t rectCount,
78234028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski                                               const VkClearRect *pRects) {
78244028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski    bool skip = false;
782556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
78264028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski    {
78274028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski        std::lock_guard<std::mutex> lock(global_lock);
78284028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski        skip = PreCallValidateCmdClearAttachments(dev_data, commandBuffer, attachmentCount, pAttachments, rectCount, pRects);
78294028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski    }
7830cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdClearAttachments(commandBuffer, attachmentCount, pAttachments, rectCount, pRects);
78315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
78325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
78330482c55760707900fcd072f6895c121bcf055f6eMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
78340482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski                                              const VkClearColorValue *pColor, uint32_t rangeCount,
78350482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski                                              const VkImageSubresourceRange *pRanges) {
783656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7837b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
78380482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski
78390482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    bool skip = PreCallValidateCmdClearColorImage(dev_data, commandBuffer, image, imageLayout, rangeCount, pRanges);
78400482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    if (!skip) {
78410482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        PreCallRecordCmdClearImage(dev_data, commandBuffer, image, imageLayout, rangeCount, pRanges, CMD_CLEARCOLORIMAGE);
78420482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        lock.unlock();
78430482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        dev_data->dispatch_table.CmdClearColorImage(commandBuffer, image, imageLayout, pColor, rangeCount, pRanges);
78440482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    }
78450482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski}
78460482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski
78470482c55760707900fcd072f6895c121bcf055f6eMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
78480482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski                                                     const VkClearDepthStencilValue *pDepthStencil, uint32_t rangeCount,
78490482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski                                                     const VkImageSubresourceRange *pRanges) {
785056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
78510482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    std::unique_lock<std::mutex> lock(global_lock);
78520482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski
78530482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    bool skip = PreCallValidateCmdClearDepthStencilImage(dev_data, commandBuffer, image, imageLayout, rangeCount, pRanges);
78540482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    if (!skip) {
78550482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        PreCallRecordCmdClearImage(dev_data, commandBuffer, image, imageLayout, rangeCount, pRanges, CMD_CLEARDEPTHSTENCILIMAGE);
78560482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        lock.unlock();
78570482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        dev_data->dispatch_table.CmdClearDepthStencilImage(commandBuffer, image, imageLayout, pDepthStencil, rangeCount, pRanges);
78587f8aa8f5abceedbb599ef69af1dfbb38c0df2660Slawomir Cygan    }
78595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
78605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7861bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
7862bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
7863bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           const VkImageResolve *pRegions) {
786456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7865b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7866593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
78679a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
78689a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto src_image_state = GetImageState(dev_data, srcImage);
78699a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto dst_image_state = GetImageState(dev_data, dstImage);
787009fe5ac5edaec7f0dbcc9fd696e68194569aea89Mark Lobodzinski
787125f7873c9ce3ed39d18bba8750d7538905e150dfMark Lobodzinski    bool skip = PreCallValidateCmdResolveImage(dev_data, cb_node, src_image_state, dst_image_state, regionCount, pRegions);
787209fe5ac5edaec7f0dbcc9fd696e68194569aea89Mark Lobodzinski
787309fe5ac5edaec7f0dbcc9fd696e68194569aea89Mark Lobodzinski    if (!skip) {
78746c0400e625554ce7fddb833eeace0de19cfcc965Mark Lobodzinski        PreCallRecordCmdResolveImage(dev_data, cb_node, src_image_state, dst_image_state);
78756c0400e625554ce7fddb833eeace0de19cfcc965Mark Lobodzinski        lock.unlock();
78764a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdResolveImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
78774a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                 pRegions);
787809fe5ac5edaec7f0dbcc9fd696e68194569aea89Mark Lobodzinski    }
78795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
78805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7881a8d1e377bdeaf61a3209cb997502da4356a185bbMike WeiblenVKAPI_ATTR void VKAPI_CALL GetImageSubresourceLayout(VkDevice device, VkImage image, const VkImageSubresource *pSubresource,
7882a8d1e377bdeaf61a3209cb997502da4356a185bbMike Weiblen                                                     VkSubresourceLayout *pLayout) {
7883a8d1e377bdeaf61a3209cb997502da4356a185bbMike Weiblen    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
7884a8d1e377bdeaf61a3209cb997502da4356a185bbMike Weiblen
7885a8d1e377bdeaf61a3209cb997502da4356a185bbMike Weiblen    bool skip = PreCallValidateGetImageSubresourceLayout(device_data, image, pSubresource);
7886a8d1e377bdeaf61a3209cb997502da4356a185bbMike Weiblen    if (!skip) {
7887b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski        device_data->dispatch_table.GetImageSubresourceLayout(device, image, pSubresource, pLayout);
7888b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski    }
7889b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski}
7890b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski
7891b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentinebool setEventStageMask(VkQueue queue, VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
789256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
78939a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
7894b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    if (pCB) {
7895b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        pCB->eventToStageMap[event] = stageMask;
7896b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
7897b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    auto queue_data = dev_data->queueMap.find(queue);
7898b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    if (queue_data != dev_data->queueMap.end()) {
7899b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        queue_data->second.eventToStageMap[event] = stageMask;
7900b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
7901b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    return false;
7902b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine}
7903b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine
7904bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
790583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
790656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7907b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
79089a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
79095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
791029f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETEVENT, "vkCmdSetEvent()");
79111ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETEVENT);
7912ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen        skip_call |= insideRenderPass(dev_data, pCB, "vkCmdSetEvent()", VALIDATION_ERROR_00238);
7913208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip_call |=
7914208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis            ValidateStageMaskGsTsEnables(dev_data, stageMask, "vkCmdSetEvent()", VALIDATION_ERROR_00230, VALIDATION_ERROR_00231);
79159a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto event_state = GetEventNode(dev_data, event);
79164710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        if (event_state) {
79174710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis            addCommandBufferBinding(&event_state->cb_bindings,
7918ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis                                    {reinterpret_cast<uint64_t &>(event), VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT}, pCB);
79194710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis            event_state->cb_bindings.insert(pCB);
7920ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis        }
79215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->events.push_back(event);
7922c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine        if (!pCB->waitedEvents.count(event)) {
7923c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine            pCB->writeEventsBeforeWait.push_back(event);
7924c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine        }
7925b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        std::function<bool(VkQueue)> eventUpdate =
7926b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            std::bind(setEventStageMask, std::placeholders::_1, commandBuffer, event, stageMask);
7927b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        pCB->eventUpdates.push_back(eventUpdate);
79285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7929b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7930cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetEvent(commandBuffer, event, stageMask);
79315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
79325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7933bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdResetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
793483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
793556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7936b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
79379a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
79385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
793929f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_RESETEVENT, "vkCmdResetEvent()");
79401ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_RESETEVENT);
7941ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen        skip_call |= insideRenderPass(dev_data, pCB, "vkCmdResetEvent()", VALIDATION_ERROR_00249);
7942208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip_call |=
7943208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis            ValidateStageMaskGsTsEnables(dev_data, stageMask, "vkCmdResetEvent()", VALIDATION_ERROR_00240, VALIDATION_ERROR_00241);
79449a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto event_state = GetEventNode(dev_data, event);
79454710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        if (event_state) {
79464710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis            addCommandBufferBinding(&event_state->cb_bindings,
7947ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis                                    {reinterpret_cast<uint64_t &>(event), VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT}, pCB);
79484710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis            event_state->cb_bindings.insert(pCB);
7949ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis        }
79505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->events.push_back(event);
7951c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine        if (!pCB->waitedEvents.count(event)) {
7952c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine            pCB->writeEventsBeforeWait.push_back(event);
7953c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine        }
7954208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        // TODO : Add check for VALIDATION_ERROR_00226
7955b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        std::function<bool(VkQueue)> eventUpdate =
7956b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            std::bind(setEventStageMask, std::placeholders::_1, commandBuffer, event, VkPipelineStageFlags(0));
7957b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        pCB->eventUpdates.push_back(eventUpdate);
79585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7959b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7960cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdResetEvent(commandBuffer, event, stageMask);
79615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
79625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7963e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool ValidateBarriers(const char *funcName, VkCommandBuffer cmdBuffer, uint32_t memBarrierCount,
7964e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                             const VkMemoryBarrier *pMemBarriers, uint32_t bufferBarrierCount,
7965e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                             const VkBufferMemoryBarrier *pBufferMemBarriers, uint32_t imageMemBarrierCount,
7966e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                             const VkImageMemoryBarrier *pImageMemBarriers) {
7967a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis    bool skip = false;
796856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(cmdBuffer), layer_data_map);
79699a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, cmdBuffer);
79705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB->activeRenderPass && memBarrierCount) {
7971ee691f5c5fa87aac3750454d2bca2cb582e4e817Chris Forbes        if (!pCB->activeRenderPass->hasSelfDependency[pCB->activeSubpass]) {
7972a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
7973cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            DRAWSTATE_INVALID_BARRIER, "DS",
7974cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s: Barriers cannot be set during subpass %d "
7975cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "with no self dependency specified.",
7976a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            funcName, pCB->activeSubpass);
79775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
79785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
79795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < imageMemBarrierCount; ++i) {
79805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto mem_barrier = &pImageMemBarriers[i];
79819a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto image_data = GetImageState(dev_data, mem_barrier->image);
79826d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis        if (image_data) {
79835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t src_q_f_index = mem_barrier->srcQueueFamilyIndex;
79845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t dst_q_f_index = mem_barrier->dstQueueFamilyIndex;
79856d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            if (image_data->createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) {
79865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // srcQueueFamilyIndex and dstQueueFamilyIndex must both
79875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // be VK_QUEUE_FAMILY_IGNORED
79885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if ((src_q_f_index != VK_QUEUE_FAMILY_IGNORED) || (dst_q_f_index != VK_QUEUE_FAMILY_IGNORED)) {
7989cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip |=
7990cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
7991cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                DRAWSTATE_INVALID_QUEUE_INDEX, "DS", "%s: Image Barrier for image 0x%" PRIx64
7992cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                                     " was created with sharingMode of "
7993cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                                     "VK_SHARING_MODE_CONCURRENT. Src and dst "
7994cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                                     "queueFamilyIndices must be VK_QUEUE_FAMILY_IGNORED.",
7995cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                funcName, reinterpret_cast<const uint64_t &>(mem_barrier->image));
79965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
79975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else {
79985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // Sharing mode is VK_SHARING_MODE_EXCLUSIVE. srcQueueFamilyIndex and
79995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // dstQueueFamilyIndex must either both be VK_QUEUE_FAMILY_IGNORED,
80005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // or both be a valid queue family
80015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (((src_q_f_index == VK_QUEUE_FAMILY_IGNORED) || (dst_q_f_index == VK_QUEUE_FAMILY_IGNORED)) &&
80025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    (src_q_f_index != dst_q_f_index)) {
8003a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                    skip |=
80045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8005cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                DRAWSTATE_INVALID_QUEUE_INDEX, "DS", "%s: Image 0x%" PRIx64
8006cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                                     " was created with sharingMode "
80075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                                     "of VK_SHARING_MODE_EXCLUSIVE. If one of src- or "
80085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                                     "dstQueueFamilyIndex is VK_QUEUE_FAMILY_IGNORED, both "
80095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                                     "must be.",
80105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                funcName, reinterpret_cast<const uint64_t &>(mem_barrier->image));
80115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                } else if (((src_q_f_index != VK_QUEUE_FAMILY_IGNORED) && (dst_q_f_index != VK_QUEUE_FAMILY_IGNORED)) &&
8012b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis                           ((src_q_f_index >= dev_data->phys_dev_properties.queue_family_properties.size()) ||
8013b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis                            (dst_q_f_index >= dev_data->phys_dev_properties.queue_family_properties.size()))) {
8014a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
8015a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                    __LINE__, DRAWSTATE_INVALID_QUEUE_INDEX, "DS",
8016cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    "%s: Image 0x%" PRIx64
8017cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    " was created with sharingMode "
8018a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                    "of VK_SHARING_MODE_EXCLUSIVE, but srcQueueFamilyIndex %d"
8019a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                    " or dstQueueFamilyIndex %d is greater than " PRINTF_SIZE_T_SPECIFIER
8020a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                    "queueFamilies crated for this device.",
8021a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                    funcName, reinterpret_cast<const uint64_t &>(mem_barrier->image), src_q_f_index, dst_q_f_index,
8022a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                    dev_data->phys_dev_properties.queue_family_properties.size());
80235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
80245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
80255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
80265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
80275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (mem_barrier) {
8028d678ec4f57d80aa89c24562e9ffe941d8d69e455Tony Barbour            if (mem_barrier->oldLayout != mem_barrier->newLayout) {
8029a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                skip |=
8030d678ec4f57d80aa89c24562e9ffe941d8d69e455Tony Barbour                    ValidateMaskBitsFromLayouts(dev_data, cmdBuffer, mem_barrier->srcAccessMask, mem_barrier->oldLayout, "Source");
8031a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                skip |=
8032d678ec4f57d80aa89c24562e9ffe941d8d69e455Tony Barbour                    ValidateMaskBitsFromLayouts(dev_data, cmdBuffer, mem_barrier->dstAccessMask, mem_barrier->newLayout, "Dest");
8033d678ec4f57d80aa89c24562e9ffe941d8d69e455Tony Barbour            }
80345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (mem_barrier->newLayout == VK_IMAGE_LAYOUT_UNDEFINED || mem_barrier->newLayout == VK_IMAGE_LAYOUT_PREINITIALIZED) {
8035a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8036cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                DRAWSTATE_INVALID_BARRIER, "DS",
8037cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                "%s: Image Layout cannot be transitioned to UNDEFINED or "
8038cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                "PREINITIALIZED.",
8039a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                funcName);
80405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
80411d5109d5e0dcc530b27e632e73e1be5e12a28dcdJamie Madill            VkFormat format = VK_FORMAT_UNDEFINED;
80421d5109d5e0dcc530b27e632e73e1be5e12a28dcdJamie Madill            uint32_t arrayLayers = 0, mipLevels = 0;
80435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            bool imageFound = false;
80446d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            if (image_data) {
80456d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis                format = image_data->createInfo.format;
80466d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis                arrayLayers = image_data->createInfo.arrayLayers;
80476d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis                mipLevels = image_data->createInfo.mipLevels;
80485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                imageFound = true;
80495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else if (dev_data->device_extensions.wsi_enabled) {
80509a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto imageswap_data = GetSwapchainFromImage(dev_data, mem_barrier->image);
8051170dc65b45f6bcdec47e02b3aa19435e55b32804Tobin Ehlis                if (imageswap_data) {
80529a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto swapchain_data = GetSwapchainNode(dev_data, imageswap_data);
8053b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis                    if (swapchain_data) {
8054b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis                        format = swapchain_data->createInfo.imageFormat;
8055b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis                        arrayLayers = swapchain_data->createInfo.imageArrayLayers;
80565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        mipLevels = 1;
80575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        imageFound = true;
80585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
80595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
80605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
80615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (imageFound) {
8062e08b485346524a30ddfe6526f7dcbbf78c776d10Mark Lobodzinski                skip |= ValidateImageSubrangeLevelLayerCounts(dev_data, mem_barrier->subresourceRange, funcName);
8063c37c65e9ff3a0abc86e706ee61d21e1dec882731Tobin Ehlis                auto aspect_mask = mem_barrier->subresourceRange.aspectMask;
8064a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                skip |= ValidateImageAspectMask(dev_data, image_data->image, format, aspect_mask, funcName);
8065f0d091deca3d4b90e1f31d75e062684dca160ad1Michael Lentine                int layerCount = (mem_barrier->subresourceRange.layerCount == VK_REMAINING_ARRAY_LAYERS)
8066f0d091deca3d4b90e1f31d75e062684dca160ad1Michael Lentine                                     ? 1
8067f0d091deca3d4b90e1f31d75e062684dca160ad1Michael Lentine                                     : mem_barrier->subresourceRange.layerCount;
8068f0d091deca3d4b90e1f31d75e062684dca160ad1Michael Lentine                if ((mem_barrier->subresourceRange.baseArrayLayer + layerCount) > arrayLayers) {
8069a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
8070cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    __LINE__, DRAWSTATE_INVALID_BARRIER, "DS",
8071cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    "%s: Subresource must have the sum of the "
8072cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    "baseArrayLayer (%d) and layerCount (%d) be less "
8073cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    "than or equal to the total number of layers (%d).",
8074a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                    funcName, mem_barrier->subresourceRange.baseArrayLayer,
8075a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                    mem_barrier->subresourceRange.layerCount, arrayLayers);
80765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
8077f0d091deca3d4b90e1f31d75e062684dca160ad1Michael Lentine                int levelCount = (mem_barrier->subresourceRange.levelCount == VK_REMAINING_MIP_LEVELS)
8078f0d091deca3d4b90e1f31d75e062684dca160ad1Michael Lentine                                     ? 1
8079f0d091deca3d4b90e1f31d75e062684dca160ad1Michael Lentine                                     : mem_barrier->subresourceRange.levelCount;
8080f0d091deca3d4b90e1f31d75e062684dca160ad1Michael Lentine                if ((mem_barrier->subresourceRange.baseMipLevel + levelCount) > mipLevels) {
8081cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
8082cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    __LINE__, DRAWSTATE_INVALID_BARRIER, "DS",
8083cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    "%s: Subresource must have the sum of the baseMipLevel "
8084cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    "(%d) and levelCount (%d) be less than or equal to "
8085cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    "the total number of levels (%d).",
8086cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    funcName, mem_barrier->subresourceRange.baseMipLevel, mem_barrier->subresourceRange.levelCount,
8087cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    mipLevels);
80885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
80895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
80905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
80915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
80925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < bufferBarrierCount; ++i) {
80935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto mem_barrier = &pBufferMemBarriers[i];
80945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (pCB->activeRenderPass) {
8095a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8096a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            DRAWSTATE_INVALID_BARRIER, "DS", "%s: Buffer Barriers cannot be used during a render pass.", funcName);
80975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8098cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!mem_barrier) continue;
80995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
81005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Validate buffer barrier queue family indices
81015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if ((mem_barrier->srcQueueFamilyIndex != VK_QUEUE_FAMILY_IGNORED &&
8102b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis             mem_barrier->srcQueueFamilyIndex >= dev_data->phys_dev_properties.queue_family_properties.size()) ||
81035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            (mem_barrier->dstQueueFamilyIndex != VK_QUEUE_FAMILY_IGNORED &&
8104b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis             mem_barrier->dstQueueFamilyIndex >= dev_data->phys_dev_properties.queue_family_properties.size())) {
8105a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8106a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            DRAWSTATE_INVALID_QUEUE_INDEX, "DS",
8107cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s: Buffer Barrier 0x%" PRIx64
8108cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            " has QueueFamilyIndex greater "
8109a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            "than the number of QueueFamilies (" PRINTF_SIZE_T_SPECIFIER ") for this device.",
8110a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            funcName, reinterpret_cast<const uint64_t &>(mem_barrier->buffer),
8111a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            dev_data->phys_dev_properties.queue_family_properties.size());
81125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
81135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
81149a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto buffer_state = GetBufferState(dev_data, mem_barrier->buffer);
81155cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        if (buffer_state) {
81165cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            auto buffer_size = buffer_state->requirements.size;
81175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (mem_barrier->offset >= buffer_size) {
8118a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8119a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                DRAWSTATE_INVALID_BARRIER, "DS", "%s: Buffer Barrier 0x%" PRIx64 " has offset 0x%" PRIx64
8120a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                                                 " which is not less than total size 0x%" PRIx64 ".",
8121a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                funcName, reinterpret_cast<const uint64_t &>(mem_barrier->buffer),
8122a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                reinterpret_cast<const uint64_t &>(mem_barrier->offset),
8123a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                reinterpret_cast<const uint64_t &>(buffer_size));
81245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else if (mem_barrier->size != VK_WHOLE_SIZE && (mem_barrier->offset + mem_barrier->size > buffer_size)) {
8125a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                skip |= log_msg(
812694c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8127414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                    DRAWSTATE_INVALID_BARRIER, "DS", "%s: Buffer Barrier 0x%" PRIx64 " has offset 0x%" PRIx64 " and size 0x%" PRIx64
8128414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                                                     " whose sum is greater than total size 0x%" PRIx64 ".",
812994c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis                    funcName, reinterpret_cast<const uint64_t &>(mem_barrier->buffer),
813094c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis                    reinterpret_cast<const uint64_t &>(mem_barrier->offset), reinterpret_cast<const uint64_t &>(mem_barrier->size),
813194c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis                    reinterpret_cast<const uint64_t &>(buffer_size));
81325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
81335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
81345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8135a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis    return skip;
81365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
81375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8138bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskibool validateEventStageMask(VkQueue queue, GLOBAL_CB_NODE *pCB, uint32_t eventCount, size_t firstEventIndex,
8139bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            VkPipelineStageFlags sourceStageMask) {
8140b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    bool skip_call = false;
8141b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    VkPipelineStageFlags stageMask = 0;
814256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
8143b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    for (uint32_t i = 0; i < eventCount; ++i) {
81442ab14387df9b890fe4b13494ea249dd03cf898d2Chris Forbes        auto event = pCB->events[firstEventIndex + i];
8145b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        auto queue_data = dev_data->queueMap.find(queue);
8146cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (queue_data == dev_data->queueMap.end()) return false;
81472ab14387df9b890fe4b13494ea249dd03cf898d2Chris Forbes        auto event_data = queue_data->second.eventToStageMap.find(event);
8148b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        if (event_data != queue_data->second.eventToStageMap.end()) {
8149b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            stageMask |= event_data->second;
8150b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        } else {
81519a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto global_event_data = GetEventNode(dev_data, event);
81529556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis            if (!global_event_data) {
8153b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT,
815427c3e0dda9e30d1d334728bbd373e8d7011257d4Chris Forbes                                     reinterpret_cast<const uint64_t &>(event), __LINE__, DRAWSTATE_INVALID_EVENT, "DS",
815527c3e0dda9e30d1d334728bbd373e8d7011257d4Chris Forbes                                     "Event 0x%" PRIx64 " cannot be waited on if it has never been set.",
81562ab14387df9b890fe4b13494ea249dd03cf898d2Chris Forbes                                     reinterpret_cast<const uint64_t &>(event));
8157b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            } else {
81589556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis                stageMask |= global_event_data->stageMask;
8159b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            }
8160b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        }
8161b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
8162c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    // TODO: Need to validate that host_bit is only set if set event is called
8163c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    // but set event can be called at any time.
8164c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    if (sourceStageMask != stageMask && sourceStageMask != (stageMask | VK_PIPELINE_STAGE_HOST_BIT)) {
8165c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8166cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             VALIDATION_ERROR_00254, "DS",
8167cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "Submitting cmdbuffer with call to VkCmdWaitEvents "
8168cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "using srcStageMask 0x%X which must be the bitwise "
8169cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "OR of the stageMask parameters used in calls to "
8170cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "vkCmdSetEvent and VK_PIPELINE_STAGE_HOST_BIT if "
8171cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "used with vkSetEvent but instead is 0x%X. %s",
81729bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             sourceStageMask, stageMask, validation_error_map[VALIDATION_ERROR_00254]);
8173b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
8174b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    return skip_call;
8175b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine}
8176b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine
817707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski// Note that we only check bits that HAVE required queueflags -- don't care entries are skipped
817807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinskistatic std::unordered_map<VkPipelineStageFlags, VkQueueFlags> supported_pipeline_stages_table = {
817907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT},
818007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT},
818107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_QUEUE_GRAPHICS_BIT},
818207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
818307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
818407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
818507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
818607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
818707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, VK_QUEUE_GRAPHICS_BIT},
818807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_QUEUE_GRAPHICS_BIT},
818907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_QUEUE_GRAPHICS_BIT},
819007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_QUEUE_COMPUTE_BIT},
819107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_TRANSFER_BIT, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT},
819207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_QUEUE_GRAPHICS_BIT}};
819307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
819407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinskistatic const VkPipelineStageFlags stage_flag_bit_array[] = {VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX,
819507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,
819607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
819707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
819807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT,
819907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT,
820007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT,
820107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
820207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
820307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
820407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
820507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
820607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_TRANSFER_BIT,
820707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT};
820807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
820907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinskibool CheckStageMaskQueueCompatibility(layer_data *dev_data, VkCommandBuffer command_buffer, VkPipelineStageFlags stage_mask,
821007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                      VkQueueFlags queue_flags, const char *function, const char *src_or_dest,
821107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                      UNIQUE_VALIDATION_ERROR_CODE error_code) {
821207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    bool skip = false;
821307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    // Lookup each bit in the stagemask and check for overlap between its table bits and queue_flags
821407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    for (const auto &item : stage_flag_bit_array) {
821507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        if (stage_mask & item) {
821607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski            if ((supported_pipeline_stages_table[item] & queue_flags) == 0) {
821707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                skip |=
821807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
821907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            reinterpret_cast<uint64_t &>(command_buffer), __LINE__, error_code, "DL",
822007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            "%s(): %s flag %s is not compatible with the queue family properties of this "
822107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            "command buffer. %s",
822207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            function, src_or_dest, string_VkPipelineStageFlagBits(static_cast<VkPipelineStageFlagBits>(item)),
822307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            validation_error_map[error_code]);
822407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski            }
822507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        }
822607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    }
822707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    return skip;
822807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski}
822907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
823007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinskibool ValidateStageMasksAgainstQueueCapabilities(layer_data *dev_data, GLOBAL_CB_NODE *cb_state,
823107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                VkPipelineStageFlags source_stage_mask, VkPipelineStageFlags dest_stage_mask,
823207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                const char *function, UNIQUE_VALIDATION_ERROR_CODE error_code) {
823307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    bool skip = false;
823407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    uint32_t queue_family_index = dev_data->commandPoolMap[cb_state->createInfo.commandPool].queueFamilyIndex;
823556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(dev_data->physical_device), instance_layer_data_map);
82369a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, dev_data->physical_device);
823707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
823807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    // Any pipeline stage included in srcStageMask or dstStageMask must be supported by the capabilities of the queue family
823907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    // specified by the queueFamilyIndex member of the VkCommandPoolCreateInfo structure that was used to create the VkCommandPool
824007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    // that commandBuffer was allocated from, as specified in the table of supported pipeline stages.
824107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
824207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    if (queue_family_index < physical_device_state->queue_family_properties.size()) {
824307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        VkQueueFlags specified_queue_flags = physical_device_state->queue_family_properties[queue_family_index].queueFlags;
824407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
824507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        if ((source_stage_mask & VK_PIPELINE_STAGE_ALL_COMMANDS_BIT) == 0) {
824607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski            skip |= CheckStageMaskQueueCompatibility(dev_data, cb_state->commandBuffer, source_stage_mask, specified_queue_flags,
824707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                     function, "srcStageMask", error_code);
824807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        }
824907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        if ((dest_stage_mask & VK_PIPELINE_STAGE_ALL_COMMANDS_BIT) == 0) {
825007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski            skip |= CheckStageMaskQueueCompatibility(dev_data, cb_state->commandBuffer, dest_stage_mask, specified_queue_flags,
825107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                     function, "dstStageMask", error_code);
825207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        }
825307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    }
825407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    return skip;
825507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski}
825607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
8257d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents,
8258d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                         VkPipelineStageFlags sourceStageMask, VkPipelineStageFlags dstStageMask,
8259d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                         uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
8260d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                         uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
8261d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                         uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
8262d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    bool skip = false;
826356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8264b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
82659a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
8266d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    if (cb_state) {
8267d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        skip |= ValidateStageMasksAgainstQueueCapabilities(dev_data, cb_state, sourceStageMask, dstStageMask, "vkCmdWaitEvents",
8268d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                                           VALIDATION_ERROR_02510);
8269208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip |= ValidateStageMaskGsTsEnables(dev_data, sourceStageMask, "vkCmdWaitEvents()", VALIDATION_ERROR_02067,
8270208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                                             VALIDATION_ERROR_02069);
8271208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip |= ValidateStageMaskGsTsEnables(dev_data, dstStageMask, "vkCmdWaitEvents()", VALIDATION_ERROR_02068,
8272208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                                             VALIDATION_ERROR_02070);
8273d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        auto first_event_index = cb_state->events.size();
82745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < eventCount; ++i) {
82759a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto event_state = GetEventNode(dev_data, pEvents[i]);
82764710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis            if (event_state) {
82774710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis                addCommandBufferBinding(&event_state->cb_bindings,
8278ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis                                        {reinterpret_cast<const uint64_t &>(pEvents[i]), VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT},
8279d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                        cb_state);
8280d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                event_state->cb_bindings.insert(cb_state);
8281ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis            }
8282d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski            cb_state->waitedEvents.insert(pEvents[i]);
8283d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski            cb_state->events.push_back(pEvents[i]);
82845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8285d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        std::function<bool(VkQueue)> event_update =
8286d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski            std::bind(validateEventStageMask, std::placeholders::_1, cb_state, eventCount, first_event_index, sourceStageMask);
8287d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        cb_state->eventUpdates.push_back(event_update);
8288ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        skip |= ValidateCmd(dev_data, cb_state, CMD_WAITEVENTS, "vkCmdWaitEvents()");
8289ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        UpdateCmdBufferLastCmd(cb_state, CMD_WAITEVENTS);
8290e659c986db0f3146726d6c744c75772316c3e0c6Mark Lobodzinski        skip |= ValidateImageLayouts(dev_data, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers);
8291e659c986db0f3146726d6c744c75772316c3e0c6Mark Lobodzinski        if (!skip) {
8292e659c986db0f3146726d6c744c75772316c3e0c6Mark Lobodzinski            TransitionImageLayouts(dev_data, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers);
8293e659c986db0f3146726d6c744c75772316c3e0c6Mark Lobodzinski        }
8294e659c986db0f3146726d6c744c75772316c3e0c6Mark Lobodzinski
8295364a03b109f0b2b37be2e13d293fa93b8af5203aMike Weiblen        skip |= ValidateBarriers("vkCmdWaitEvents()", commandBuffer, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
8296d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                 pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
82975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8298b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8299d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    if (!skip)
83004a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdWaitEvents(commandBuffer, eventCount, pEvents, sourceStageMask, dstStageMask,
83014a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                               memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers,
83024a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                               imageMemoryBarrierCount, pImageMemoryBarriers);
83035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
83045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
830503122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinskistatic bool PreCallValidateCmdPipelineBarrier(layer_data *device_data, GLOBAL_CB_NODE *cb_state, VkCommandBuffer commandBuffer,
830603122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                              VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask,
830703122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                              uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
830803122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                              uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
830903122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                              uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
831003122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    bool skip = false;
831103122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    skip |= ValidateStageMasksAgainstQueueCapabilities(device_data, cb_state, srcStageMask, dstStageMask, "vkCmdPipelineBarrier",
831203122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                                       VALIDATION_ERROR_02513);
831303122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    skip |= ValidateCmd(device_data, cb_state, CMD_PIPELINEBARRIER, "vkCmdPipelineBarrier()");
831403122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    skip |= ValidateStageMaskGsTsEnables(device_data, srcStageMask, "vkCmdPipelineBarrier()", VALIDATION_ERROR_00265,
831503122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                         VALIDATION_ERROR_00267);
831603122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    skip |= ValidateStageMaskGsTsEnables(device_data, dstStageMask, "vkCmdPipelineBarrier()", VALIDATION_ERROR_00266,
831703122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                         VALIDATION_ERROR_00268);
831803122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    UpdateCmdBufferLastCmd(cb_state, CMD_PIPELINEBARRIER);
8319e659c986db0f3146726d6c744c75772316c3e0c6Mark Lobodzinski    skip |= ValidateImageLayouts(device_data, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers);
8320e659c986db0f3146726d6c744c75772316c3e0c6Mark Lobodzinski    if (!skip) {
8321e659c986db0f3146726d6c744c75772316c3e0c6Mark Lobodzinski        TransitionImageLayouts(device_data, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers);
8322e659c986db0f3146726d6c744c75772316c3e0c6Mark Lobodzinski    }
832303122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    skip |= ValidateBarriers("vkCmdPipelineBarrier()", commandBuffer, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
832403122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                             pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
832503122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    return skip;
832603122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski}
832703122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski
8328d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask,
8329d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                              VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags,
8330d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                              uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
8331d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                              uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
8332d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                              uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
8333d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    bool skip = false;
833456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8335b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
83369a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
8337d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    if (cb_state) {
833803122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski        skip |= PreCallValidateCmdPipelineBarrier(dev_data, cb_state, commandBuffer, srcStageMask, dstStageMask,
833903122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                                  memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
834003122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                                  pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
83415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8342b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8343d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    if (!skip)
83444a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, dependencyFlags, memoryBarrierCount,
83454a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                    pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers,
83464a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                    imageMemoryBarrierCount, pImageMemoryBarriers);
83475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
83485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8349d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentinebool setQueryState(VkQueue queue, VkCommandBuffer commandBuffer, QueryObject object, bool value) {
835056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
83519a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
8352d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    if (pCB) {
8353d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        pCB->queryToStateMap[object] = value;
8354d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    }
8355d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    auto queue_data = dev_data->queueMap.find(queue);
8356d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    if (queue_data != dev_data->queueMap.end()) {
8357d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        queue_data->second.queryToStateMap[object] = value;
8358d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    }
8359d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    return false;
8360d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine}
8361d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine
8362bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBeginQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot, VkFlags flags) {
836383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
836456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8365b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
83669a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
83675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
83685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        QueryObject query = {queryPool, slot};
83695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->activeQueries.insert(query);
83705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!pCB->startedQueries.count(query)) {
83715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pCB->startedQueries.insert(query);
83725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
837329f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_BEGINQUERY, "vkCmdBeginQuery()");
83741ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_BEGINQUERY);
83759a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        addCommandBufferBinding(&GetQueryPoolNode(dev_data, queryPool)->cb_bindings,
8376ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis                                {reinterpret_cast<uint64_t &>(queryPool), VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT}, pCB);
83775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8378b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8379cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdBeginQuery(commandBuffer, queryPool, slot, flags);
83805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
83815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
838289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdEndQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot) {
8383946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
838456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8385b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
8386946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
8387946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (cb_state) {
83885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        QueryObject query = {queryPool, slot};
8389946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        if (!cb_state->activeQueries.count(query)) {
8390946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            skip |=
83915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
83929bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        VALIDATION_ERROR_01041, "DS", "Ending a query before it was started: queryPool 0x%" PRIx64 ", index %d. %s",
83939bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        (uint64_t)(queryPool), slot, validation_error_map[VALIDATION_ERROR_01041]);
83945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
8395946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            cb_state->activeQueries.erase(query);
83965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8397946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        std::function<bool(VkQueue)> query_update = std::bind(setQueryState, std::placeholders::_1, commandBuffer, query, true);
8398946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        cb_state->queryUpdates.push_back(query_update);
8399946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_state, CMD_ENDQUERY, "VkCmdEndQuery()");
8400946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        UpdateCmdBufferLastCmd(cb_state, CMD_ENDQUERY);
84019a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        addCommandBufferBinding(&GetQueryPoolNode(dev_data, queryPool)->cb_bindings,
8402946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                {reinterpret_cast<uint64_t &>(queryPool), VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT}, cb_state);
84035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8404b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8405946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdEndQuery(commandBuffer, queryPool, slot);
84065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
84075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8408bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdResetQueryPool(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery,
8409bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                             uint32_t queryCount) {
8410946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
841156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8412b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
8413946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
8414946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (cb_state) {
84155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < queryCount; i++) {
84165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            QueryObject query = {queryPool, firstQuery + i};
8417946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            cb_state->waitedEventsBeforeQueryReset[query] = cb_state->waitedEvents;
8418946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            std::function<bool(VkQueue)> query_update =
8419946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                std::bind(setQueryState, std::placeholders::_1, commandBuffer, query, false);
8420946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            cb_state->queryUpdates.push_back(query_update);
8421946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        }
8422946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_state, CMD_RESETQUERYPOOL, "VkCmdResetQueryPool()");
8423946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        UpdateCmdBufferLastCmd(cb_state, CMD_RESETQUERYPOOL);
8424946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= insideRenderPass(dev_data, cb_state, "vkCmdResetQueryPool()", VALIDATION_ERROR_01025);
84259a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        addCommandBufferBinding(&GetQueryPoolNode(dev_data, queryPool)->cb_bindings,
8426946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                {reinterpret_cast<uint64_t &>(queryPool), VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT}, cb_state);
84275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8428b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8429946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdResetQueryPool(commandBuffer, queryPool, firstQuery, queryCount);
84305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
84315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8432d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentinebool validateQuery(VkQueue queue, GLOBAL_CB_NODE *pCB, VkQueryPool queryPool, uint32_t queryCount, uint32_t firstQuery) {
8433d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    bool skip_call = false;
843456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(pCB->commandBuffer), layer_data_map);
8435d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    auto queue_data = dev_data->queueMap.find(queue);
8436cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (queue_data == dev_data->queueMap.end()) return false;
8437d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    for (uint32_t i = 0; i < queryCount; i++) {
8438d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        QueryObject query = {queryPool, firstQuery + i};
8439d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        auto query_data = queue_data->second.queryToStateMap.find(query);
8440d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        bool fail = false;
8441d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        if (query_data != queue_data->second.queryToStateMap.end()) {
8442d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            if (!query_data->second) {
8443d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                fail = true;
8444d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            }
8445d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        } else {
8446d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            auto global_query_data = dev_data->queryToStateMap.find(query);
8447d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            if (global_query_data != dev_data->queryToStateMap.end()) {
8448d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                if (!global_query_data->second) {
8449d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                    fail = true;
8450d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                }
8451d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            } else {
8452d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                fail = true;
8453d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            }
8454d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        }
8455d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        if (fail) {
8456d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8457d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                                 DRAWSTATE_INVALID_QUERY, "DS",
8458d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                                 "Requesting a copy from query to buffer with invalid query: queryPool 0x%" PRIx64 ", index %d",
8459d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                                 reinterpret_cast<uint64_t &>(queryPool), firstQuery + i);
8460d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        }
8461d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    }
8462d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    return skip_call;
8463d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine}
8464d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine
8465bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdCopyQueryPoolResults(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery,
8466bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset,
8467bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   VkDeviceSize stride, VkQueryResultFlags flags) {
8468946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
846956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8470b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
8471ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
84729a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
84739a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto dst_buff_state = GetBufferState(dev_data, dstBuffer);
84745cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (cb_node && dst_buff_state) {
8475946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateMemoryIsBoundToBuffer(dev_data, dst_buff_state, "vkCmdCopyQueryPoolResults()", VALIDATION_ERROR_02526);
8476ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Update bindings between buffer and cmd buffer
84775cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        AddCommandBufferBindingBuffer(dev_data, cb_node, dst_buff_state);
8478ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Validate that DST buffer has correct usage flags set
8479946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateBufferUsageFlags(dev_data, dst_buff_state, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, VALIDATION_ERROR_01066,
8480946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                         "vkCmdCopyQueryPoolResults()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
8481e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
84825cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            SetBufferMemoryValid(dev_data, dst_buff_state, true);
8483e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
84845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        };
84859f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
8486946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        std::function<bool(VkQueue)> query_update =
8487ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis            std::bind(validateQuery, std::placeholders::_1, cb_node, queryPool, queryCount, firstQuery);
8488946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        cb_node->queryUpdates.push_back(query_update);
8489946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_node, CMD_COPYQUERYPOOLRESULTS, "vkCmdCopyQueryPoolResults()");
8490ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        UpdateCmdBufferLastCmd(cb_node, CMD_COPYQUERYPOOLRESULTS);
8491946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= insideRenderPass(dev_data, cb_node, "vkCmdCopyQueryPoolResults()", VALIDATION_ERROR_01074);
84929a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        addCommandBufferBinding(&GetQueryPoolNode(dev_data, queryPool)->cb_bindings,
8493ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis                                {reinterpret_cast<uint64_t &>(queryPool), VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT}, cb_node);
8494ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
8495ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
84965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8497b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8498946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip)
84994a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdCopyQueryPoolResults(commandBuffer, queryPool, firstQuery, queryCount, dstBuffer, dstOffset,
85004a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                         stride, flags);
85015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
85025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8503bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdPushConstants(VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags,
8504bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                            uint32_t offset, uint32_t size, const void *pValues) {
8505946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
850656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8507b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
8508946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
8509946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (cb_state) {
8510946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_state, CMD_PUSHCONSTANTS, "vkCmdPushConstants()");
8511946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        UpdateCmdBufferLastCmd(cb_state, CMD_PUSHCONSTANTS);
85125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8513946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    skip |= validatePushConstantRange(dev_data, offset, size, "vkCmdPushConstants()");
85149e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    if (0 == stageFlags) {
8515946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8516946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        VALIDATION_ERROR_00996, "DS", "vkCmdPushConstants() call has no stageFlags set. %s",
8517946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        validation_error_map[VALIDATION_ERROR_00996]);
85189e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    }
85199e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz
8520a95cb74c9d0947ab3821b15e1289755286ea78eeKarl Schultz    // Check if push constant update is within any of the ranges with the same stage flags specified in pipeline layout.
8521c2a5a36d03bbe52f5854a5884346e4a84115e259Tobin Ehlis    auto pipeline_layout = getPipelineLayout(dev_data, layout);
852215a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis    // Coalesce adjacent/overlapping pipeline ranges before checking to see if incoming range is
852315a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis    // contained in the pipeline ranges.
852415a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis    // Build a {start, end} span list for ranges with matching stage flags.
852515a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis    const auto &ranges = pipeline_layout->push_constant_ranges;
852615a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis    struct span {
852715a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        uint32_t start;
852815a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        uint32_t end;
852915a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis    };
853015a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis    std::vector<span> spans;
853115a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis    spans.reserve(ranges.size());
853215a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis    for (const auto &iter : ranges) {
853315a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        if (iter.stageFlags == stageFlags) {
853415a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis            spans.push_back({iter.offset, iter.offset + iter.size});
853515a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        }
853615a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis    }
853715a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis    if (spans.size() == 0) {
853815a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        // There were no ranges that matched the stageFlags.
8539946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8540946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        VALIDATION_ERROR_00988, "DS", "vkCmdPushConstants() stageFlags = 0x%" PRIx32
8541946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                                      " do not match "
8542946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                                      "the stageFlags in any of the ranges in pipeline layout 0x%" PRIx64 ". %s",
8543946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        (uint32_t)stageFlags, (uint64_t)layout, validation_error_map[VALIDATION_ERROR_00988]);
85449e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    } else {
854515a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        // Sort span list by start value.
854615a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        struct comparer {
854715a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis            bool operator()(struct span i, struct span j) { return i.start < j.start; }
854815a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        } my_comparer;
854915a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        std::sort(spans.begin(), spans.end(), my_comparer);
855015a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis
855115a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        // Examine two spans at a time.
855215a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        std::vector<span>::iterator current = spans.begin();
855315a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        std::vector<span>::iterator next = current + 1;
855415a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        while (next != spans.end()) {
855515a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis            if (current->end < next->start) {
855615a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                // There is a gap; cannot coalesce. Move to the next two spans.
855715a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                ++current;
855815a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                ++next;
855915a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis            } else {
856015a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                // Coalesce the two spans.  The start of the next span
856115a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                // is within the current span, so pick the larger of
856215a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                // the end values to extend the current span.
856315a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                // Then delete the next span and set next to the span after it.
856415a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                current->end = max(current->end, next->end);
856515a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                next = spans.erase(next);
85669e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz            }
85679e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
8568a95cb74c9d0947ab3821b15e1289755286ea78eeKarl Schultz
856915a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        // Now we can check if the incoming range is within any of the spans.
857015a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        bool contained_in_a_range = false;
857115a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        for (uint32_t i = 0; i < spans.size(); ++i) {
857215a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis            if ((offset >= spans[i].start) && ((uint64_t)offset + (uint64_t)size <= (uint64_t)spans[i].end)) {
857315a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                contained_in_a_range = true;
857415a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                break;
8575a95cb74c9d0947ab3821b15e1289755286ea78eeKarl Schultz            }
85769e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
857715a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        if (!contained_in_a_range) {
8578946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            skip |= log_msg(
8579946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8580946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                VALIDATION_ERROR_00988, "DS", "vkCmdPushConstants() Push constant range [%d, %d) with stageFlags = 0x%" PRIx32
8581946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                              " not within flag-matching ranges in pipeline layout 0x%" PRIx64 ". %s",
8582946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                offset, offset + size, (uint32_t)stageFlags, (uint64_t)layout, validation_error_map[VALIDATION_ERROR_00988]);
858315a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        }
85845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8585b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8586946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdPushConstants(commandBuffer, layout, stageFlags, offset, size, pValues);
85875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
85885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8589bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage,
8590bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                             VkQueryPool queryPool, uint32_t slot) {
8591946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
859256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8593b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
8594946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
8595946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (cb_state) {
85965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        QueryObject query = {queryPool, slot};
8597946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        std::function<bool(VkQueue)> query_update = std::bind(setQueryState, std::placeholders::_1, commandBuffer, query, true);
8598946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        cb_state->queryUpdates.push_back(query_update);
8599946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_state, CMD_WRITETIMESTAMP, "vkCmdWriteTimestamp()");
8600946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        UpdateCmdBufferLastCmd(cb_state, CMD_WRITETIMESTAMP);
86015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8602b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8603946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdWriteTimestamp(commandBuffer, pipelineStage, queryPool, slot);
86045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
86055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
86066600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinskistatic bool MatchUsage(layer_data *dev_data, uint32_t count, const VkAttachmentReference *attachments,
86079bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                       const VkFramebufferCreateInfo *fbci, VkImageUsageFlagBits usage_flag,
86089bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                       UNIQUE_VALIDATION_ERROR_CODE error_code) {
8609946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
86106600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
86116600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    for (uint32_t attach = 0; attach < count; attach++) {
86126600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski        if (attachments[attach].attachment != VK_ATTACHMENT_UNUSED) {
86136600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            // Attachment counts are verified elsewhere, but prevent an invalid access
86146600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            if (attachments[attach].attachment < fbci->attachmentCount) {
86156600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                const VkImageView *image_view = &fbci->pAttachments[attachments[attach].attachment];
86169a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto view_state = GetImageViewState(dev_data, *image_view);
861779fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if (view_state) {
86189a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    const VkImageCreateInfo *ici = &GetImageState(dev_data, view_state->create_info.image)->createInfo;
86196600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                    if (ici != nullptr) {
86206600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                        if ((ici->usage & usage_flag) == 0) {
8621946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
8622946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                            __LINE__, error_code, "DS",
8623946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                            "vkCreateFramebuffer:  Framebuffer Attachment (%d) conflicts with the image's "
8624946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                            "IMAGE_USAGE flags (%s). %s",
8625946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                            attachments[attach].attachment, string_VkImageUsageFlagBits(usage_flag),
8626946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                            validation_error_map[error_code]);
86276600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                        }
86286600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                    }
86296600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                }
86306600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            }
86316600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski        }
86326600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    }
8633946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    return skip;
86346600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski}
86356600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
8636d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis// Validate VkFramebufferCreateInfo which includes:
8637d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis// 1. attachmentCount equals renderPass attachmentCount
86385ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 2. corresponding framebuffer and renderpass attachments have matching formats
86395ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 3. corresponding framebuffer and renderpass attachments have matching sample counts
86405ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 4. fb attachments only have a single mip level
86415ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 5. fb attachment dimensions are each at least as large as the fb
86425ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 6. fb attachments use idenity swizzle
86435ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 7. fb attachments used by renderPass for color/input/ds have correct usage bit set
86446fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis// 8. fb dimensions are within physical device limits
8645d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlisstatic bool ValidateFramebufferCreateInfo(layer_data *dev_data, const VkFramebufferCreateInfo *pCreateInfo) {
86466600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    bool skip_call = false;
86476600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
86489a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto rp_state = GetRenderPassState(dev_data, pCreateInfo->renderPass);
8649127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis    if (rp_state) {
8650127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis        const VkRenderPassCreateInfo *rpci = rp_state->createInfo.ptr();
8651d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis        if (rpci->attachmentCount != pCreateInfo->attachmentCount) {
8652d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis            skip_call |= log_msg(
8653d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
86549bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                reinterpret_cast<const uint64_t &>(pCreateInfo->renderPass), __LINE__, VALIDATION_ERROR_00404, "DS",
8655d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis                "vkCreateFramebuffer(): VkFramebufferCreateInfo attachmentCount of %u does not match attachmentCount of %u of "
86569bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                "renderPass (0x%" PRIxLEAST64 ") being used to create Framebuffer. %s",
86579bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                pCreateInfo->attachmentCount, rpci->attachmentCount, reinterpret_cast<const uint64_t &>(pCreateInfo->renderPass),
86589bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                validation_error_map[VALIDATION_ERROR_00404]);
86595ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis        } else {
866041ebcb6b517b1de5ae456d46d866f5e84a96a2c5Tobin Ehlis            // attachmentCounts match, so make sure corresponding attachment details line up
86615ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis            const VkImageView *image_views = pCreateInfo->pAttachments;
86625ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis            for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
86639a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto view_state = GetImageViewState(dev_data, image_views[i]);
866412d5600c2f9e32343016fd944432ba95df370797Tobin Ehlis                auto &ivci = view_state->create_info;
866579fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if (ivci.format != rpci->pAttachments[i].format) {
86665ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                    skip_call |= log_msg(
86675ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
86689bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        reinterpret_cast<const uint64_t &>(pCreateInfo->renderPass), __LINE__, VALIDATION_ERROR_00408, "DS",
86699bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has format of %s that does not match "
86709bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "the format of "
86719bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "%s used by the corresponding attachment for renderPass (0x%" PRIxLEAST64 "). %s",
867279fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                        i, string_VkFormat(ivci.format), string_VkFormat(rpci->pAttachments[i].format),
86739bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        reinterpret_cast<const uint64_t &>(pCreateInfo->renderPass), validation_error_map[VALIDATION_ERROR_00408]);
86745ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
86759a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                const VkImageCreateInfo *ici = &GetImageState(dev_data, ivci.image)->createInfo;
86765ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                if (ici->samples != rpci->pAttachments[i].samples) {
867741ebcb6b517b1de5ae456d46d866f5e84a96a2c5Tobin Ehlis                    skip_call |= log_msg(
867841ebcb6b517b1de5ae456d46d866f5e84a96a2c5Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
86799bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        reinterpret_cast<const uint64_t &>(pCreateInfo->renderPass), __LINE__, VALIDATION_ERROR_00409, "DS",
86809bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has %s samples that do not match "
86819bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "the %s samples used by the corresponding attachment for renderPass (0x%" PRIxLEAST64 "). %s",
868241ebcb6b517b1de5ae456d46d866f5e84a96a2c5Tobin Ehlis                        i, string_VkSampleCountFlagBits(ici->samples), string_VkSampleCountFlagBits(rpci->pAttachments[i].samples),
86839bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        reinterpret_cast<const uint64_t &>(pCreateInfo->renderPass), validation_error_map[VALIDATION_ERROR_00409]);
86845ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
86855ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                // Verify that view only has a single mip level
868679fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if (ivci.subresourceRange.levelCount != 1) {
86879bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                    skip_call |=
86889bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
86899bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                VALIDATION_ERROR_00411, "DS",
86909bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has mip levelCount of %u "
86919bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                "but only a single mip level (levelCount ==  1) is allowed when creating a Framebuffer. %s",
86929bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                i, ivci.subresourceRange.levelCount, validation_error_map[VALIDATION_ERROR_00411]);
86935ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
869479fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                const uint32_t mip_level = ivci.subresourceRange.baseMipLevel;
8695aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                uint32_t mip_width = max(1u, ici->extent.width >> mip_level);
8696aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                uint32_t mip_height = max(1u, ici->extent.height >> mip_level);
869779fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if ((ivci.subresourceRange.layerCount < pCreateInfo->layers) || (mip_width < pCreateInfo->width) ||
8698aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                    (mip_height < pCreateInfo->height)) {
8699aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                    skip_call |=
87006fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
8701aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                DRAWSTATE_INVALID_FRAMEBUFFER_CREATE_INFO, "DS",
8702aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u mip level %u has dimensions smaller "
8703aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                "than the corresponding "
8704aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                "framebuffer dimensions. Attachment dimensions must be at least as large. Here are the respective "
8705aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                "dimensions for "
8706aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                "attachment #%u, framebuffer:\n"
8707aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                "width: %u, %u\n"
8708aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                "height: %u, %u\n"
8709aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                "layerCount: %u, %u\n",
871079fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                                i, ivci.subresourceRange.baseMipLevel, i, mip_width, pCreateInfo->width, mip_height,
871179fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                                pCreateInfo->height, ivci.subresourceRange.layerCount, pCreateInfo->layers);
87125ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
871379fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if (((ivci.components.r != VK_COMPONENT_SWIZZLE_IDENTITY) && (ivci.components.r != VK_COMPONENT_SWIZZLE_R)) ||
871479fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                    ((ivci.components.g != VK_COMPONENT_SWIZZLE_IDENTITY) && (ivci.components.g != VK_COMPONENT_SWIZZLE_G)) ||
871579fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                    ((ivci.components.b != VK_COMPONENT_SWIZZLE_IDENTITY) && (ivci.components.b != VK_COMPONENT_SWIZZLE_B)) ||
871679fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                    ((ivci.components.a != VK_COMPONENT_SWIZZLE_IDENTITY) && (ivci.components.a != VK_COMPONENT_SWIZZLE_A))) {
8717da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                    skip_call |= log_msg(
87186fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
87199bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        VALIDATION_ERROR_00412, "DS",
8720da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has non-identy swizzle. All framebuffer "
8721da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "attachments must have been created with the identity swizzle. Here are the actual swizzle values:\n"
8722da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "r swizzle = %s\n"
8723da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "g swizzle = %s\n"
8724da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "b swizzle = %s\n"
87259bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "a swizzle = %s\n"
87269bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "%s",
872779fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                        i, string_VkComponentSwizzle(ivci.components.r), string_VkComponentSwizzle(ivci.components.g),
87289bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        string_VkComponentSwizzle(ivci.components.b), string_VkComponentSwizzle(ivci.components.a),
87299bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        validation_error_map[VALIDATION_ERROR_00412]);
87305ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
87315ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis            }
8732d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis        }
87335ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis        // Verify correct attachment usage flags
87346600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski        for (uint32_t subpass = 0; subpass < rpci->subpassCount; subpass++) {
87356600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            // Verify input attachments:
87369bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt            skip_call |=
87379bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                MatchUsage(dev_data, rpci->pSubpasses[subpass].inputAttachmentCount, rpci->pSubpasses[subpass].pInputAttachments,
87389bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                           pCreateInfo, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, VALIDATION_ERROR_00407);
87396600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            // Verify color attachments:
87409bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt            skip_call |=
87419bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                MatchUsage(dev_data, rpci->pSubpasses[subpass].colorAttachmentCount, rpci->pSubpasses[subpass].pColorAttachments,
87429bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                           pCreateInfo, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VALIDATION_ERROR_00405);
87436600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            // Verify depth/stencil attachments:
87446600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            if (rpci->pSubpasses[subpass].pDepthStencilAttachment != nullptr) {
87456600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                skip_call |= MatchUsage(dev_data, 1, rpci->pSubpasses[subpass].pDepthStencilAttachment, pCreateInfo,
87469bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                        VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VALIDATION_ERROR_00406);
87476600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            }
87486600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski        }
87496600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    }
87506fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis    // Verify FB dimensions are within physical device limits
87519bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    if (pCreateInfo->width > dev_data->phys_dev_properties.properties.limits.maxFramebufferWidth) {
87526fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
87539bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             VALIDATION_ERROR_00413, "DS",
87549bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo width exceeds physical device limits. "
87559bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "Requested width: %u, device max: %u\n"
87569bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "%s",
87576fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis                             pCreateInfo->width, dev_data->phys_dev_properties.properties.limits.maxFramebufferWidth,
87589bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             validation_error_map[VALIDATION_ERROR_00413]);
87599bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    }
87609bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    if (pCreateInfo->height > dev_data->phys_dev_properties.properties.limits.maxFramebufferHeight) {
87619bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
87629bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             VALIDATION_ERROR_00414, "DS",
87639bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo height exceeds physical device limits. "
87649bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "Requested height: %u, device max: %u\n"
87659bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "%s",
87666fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis                             pCreateInfo->height, dev_data->phys_dev_properties.properties.limits.maxFramebufferHeight,
87679bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             validation_error_map[VALIDATION_ERROR_00414]);
87689bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    }
87699bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    if (pCreateInfo->layers > dev_data->phys_dev_properties.properties.limits.maxFramebufferLayers) {
87709bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
87719bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             VALIDATION_ERROR_00415, "DS",
87729bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo layers exceeds physical device limits. "
87739bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "Requested layers: %u, device max: %u\n"
87749bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "%s",
87759bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             pCreateInfo->layers, dev_data->phys_dev_properties.properties.limits.maxFramebufferLayers,
87769bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             validation_error_map[VALIDATION_ERROR_00415]);
87776fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis    }
87786600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    return skip_call;
87796600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski}
87806600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
878164c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis// Validate VkFramebufferCreateInfo state prior to calling down chain to create Framebuffer object
878264c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis//  Return true if an error is encountered and callback returns true to skip call down chain
878364c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis//   false indicates that call down chain should proceed
878464c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlisstatic bool PreCallValidateCreateFramebuffer(layer_data *dev_data, const VkFramebufferCreateInfo *pCreateInfo) {
878564c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    // TODO : Verify that renderPass FB is created with is compatible with FB
878664c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    bool skip_call = false;
8787d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis    skip_call |= ValidateFramebufferCreateInfo(dev_data, pCreateInfo);
878864c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    return skip_call;
878964c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis}
879064c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis
879154e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis// CreateFramebuffer state has been validated and call down chain completed so record new framebuffer object
879254e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlisstatic void PostCallRecordCreateFramebuffer(layer_data *dev_data, const VkFramebufferCreateInfo *pCreateInfo, VkFramebuffer fb) {
879354e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis    // Shadow create info and store in map
8794c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    std::unique_ptr<FRAMEBUFFER_STATE> fb_state(
8795c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis        new FRAMEBUFFER_STATE(fb, pCreateInfo, dev_data->renderPassMap[pCreateInfo->renderPass]->createInfo.ptr()));
879676f04ca0e692f9f15d5ef7e0c658c24d11f34ebcTobin Ehlis
879754e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
879854e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        VkImageView view = pCreateInfo->pAttachments[i];
87999a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto view_state = GetImageViewState(dev_data, view);
880079fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis        if (!view_state) {
880154e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis            continue;
880254e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        }
880354e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        MT_FB_ATTACHMENT_INFO fb_info;
88049a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        fb_info.mem = GetImageState(dev_data, view_state->create_info.image)->binding.mem;
8805883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        fb_info.view_state = view_state;
880679fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis        fb_info.image = view_state->create_info.image;
8807c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis        fb_state->attachments.push_back(fb_info);
880854e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis    }
8809c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    dev_data->frameBufferMap[fb] = std::move(fb_state);
881054e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis}
881154e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis
881289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateFramebuffer(VkDevice device, const VkFramebufferCreateInfo *pCreateInfo,
8813bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkAllocationCallbacks *pAllocator, VkFramebuffer *pFramebuffer) {
881456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
881564c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
881664c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    bool skip_call = PreCallValidateCreateFramebuffer(dev_data, pCreateInfo);
881764c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    lock.unlock();
881864c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis
8819cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
882064c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis
88214a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateFramebuffer(device, pCreateInfo, pAllocator, pFramebuffer);
88226600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
88235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
882464c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis        lock.lock();
882554e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        PostCallRecordCreateFramebuffer(dev_data, pCreateInfo, *pFramebuffer);
882654e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        lock.unlock();
88275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
88285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
88295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
88305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8831e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool FindDependency(const int index, const int dependent, const std::vector<DAGNode> &subpass_to_node,
8832e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                           std::unordered_set<uint32_t> &processed_nodes) {
88335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If we have already checked this node we have not found a dependency path so return false.
8834cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (processed_nodes.count(index)) return false;
88355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    processed_nodes.insert(index);
88365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    const DAGNode &node = subpass_to_node[index];
88375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Look for a dependency path. If one exists return true else recurse on the previous nodes.
8838593f84b63934f07483e5e5a20fd352df8ab4f8c9Bruce Dawson    if (std::find(node.prev.begin(), node.prev.end(), static_cast<uint32_t>(dependent)) == node.prev.end()) {
88395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto elem : node.prev) {
8840cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (FindDependency(elem, dependent, subpass_to_node, processed_nodes)) return true;
88415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
88425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
8843e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        return true;
88445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8845e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    return false;
88465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
88475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
88488860b85a52096f9f9b28616bc37feed505497a54Chris Forbesstatic bool CheckDependencyExists(const layer_data *dev_data, const int subpass, const std::vector<uint32_t> &dependent_subpasses,
8849e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                                  const std::vector<DAGNode> &subpass_to_node, bool &skip_call) {
8850e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool result = true;
88515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Loop through all subpasses that share the same attachment and make sure a dependency exists
88525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t k = 0; k < dependent_subpasses.size(); ++k) {
8853cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (static_cast<uint32_t>(subpass) == dependent_subpasses[k]) continue;
88545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const DAGNode &node = subpass_to_node[subpass];
88555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Check for a specified dependency between the two nodes. If one exists we are done.
88565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto prev_elem = std::find(node.prev.begin(), node.prev.end(), dependent_subpasses[k]);
88575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto next_elem = std::find(node.next.begin(), node.next.end(), dependent_subpasses[k]);
88585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (prev_elem == node.prev.end() && next_elem == node.next.end()) {
88597655cb8b5eb52badee0b011729a05afa36316d69Jan-Harald Fredriksen            // If no dependency exits an implicit dependency still might. If not, throw an error.
88605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            std::unordered_set<uint32_t> processed_nodes;
88617655cb8b5eb52badee0b011729a05afa36316d69Jan-Harald Fredriksen            if (!(FindDependency(subpass, dependent_subpasses[k], subpass_to_node, processed_nodes) ||
8862bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                  FindDependency(dependent_subpasses[k], subpass, subpass_to_node, processed_nodes))) {
88638860b85a52096f9f9b28616bc37feed505497a54Chris Forbes                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
88645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                     __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
88655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                     "A dependency between subpasses %d and %d must exist but one is not specified.", subpass,
88665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                     dependent_subpasses[k]);
8867e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                result = false;
88685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
88695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
88705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
88715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
88725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
88735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
88748860b85a52096f9f9b28616bc37feed505497a54Chris Forbesstatic bool CheckPreserved(const layer_data *dev_data, const VkRenderPassCreateInfo *pCreateInfo, const int index,
8875e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                           const uint32_t attachment, const std::vector<DAGNode> &subpass_to_node, int depth, bool &skip_call) {
88765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    const DAGNode &node = subpass_to_node[index];
88775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If this node writes to the attachment return true as next nodes need to preserve the attachment.
88785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[index];
88795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
8880cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (attachment == subpass.pColorAttachments[j].attachment) return true;
88815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8882a4ea781e8fff70c9db0bedad7fcb6bba08e35da7Tony Barbour    for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
8883a4ea781e8fff70c9db0bedad7fcb6bba08e35da7Tony Barbour        if (attachment == subpass.pInputAttachments[j].attachment) return true;
8884a4ea781e8fff70c9db0bedad7fcb6bba08e35da7Tony Barbour    }
88855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
8886cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (attachment == subpass.pDepthStencilAttachment->attachment) return true;
88875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8888e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool result = false;
88895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Loop through previous nodes and see if any of them write to the attachment.
88905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto elem : node.prev) {
88918860b85a52096f9f9b28616bc37feed505497a54Chris Forbes        result |= CheckPreserved(dev_data, pCreateInfo, elem, attachment, subpass_to_node, depth + 1, skip_call);
88925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
88935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If the attachment was written to by a previous node than this node needs to preserve it.
88945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result && depth > 0) {
8895e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        bool has_preserved = false;
88965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.preserveAttachmentCount; ++j) {
88975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (subpass.pPreserveAttachments[j] == attachment) {
8898e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                has_preserved = true;
88995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                break;
89005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
89015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8902e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        if (!has_preserved) {
89035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            skip_call |=
89048860b85a52096f9f9b28616bc37feed505497a54Chris Forbes                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
89055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        DRAWSTATE_INVALID_RENDERPASS, "DS",
89065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        "Attachment %d is used by a later subpass and must be preserved in subpass %d.", attachment, index);
89075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
89085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
89095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
89105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
89115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8912cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskitemplate <class T>
8913cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskibool isRangeOverlapping(T offset1, T size1, T offset2, T size2) {
89145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return (((offset1 + size1) > offset2) && ((offset1 + size1) < (offset2 + size2))) ||
89155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis           ((offset1 > offset2) && (offset1 < (offset2 + size2)));
89165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
89175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
89185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisbool isRegionOverlapping(VkImageSubresourceRange range1, VkImageSubresourceRange range2) {
89195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return (isRangeOverlapping(range1.baseMipLevel, range1.levelCount, range2.baseMipLevel, range2.levelCount) &&
89205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            isRangeOverlapping(range1.baseArrayLayer, range1.layerCount, range2.baseArrayLayer, range2.layerCount));
89215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
89225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8923c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlisstatic bool ValidateDependencies(const layer_data *dev_data, FRAMEBUFFER_STATE const *framebuffer,
8924127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                                 RENDER_PASS_STATE const *renderPass) {
8925e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
8926fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    auto const pFramebufferInfo = framebuffer->createInfo.ptr();
8927fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    auto const pCreateInfo = renderPass->createInfo.ptr();
8928bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto const &subpass_to_node = renderPass->subpassToNode;
89295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<std::vector<uint32_t>> output_attachment_to_subpass(pCreateInfo->attachmentCount);
89305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<std::vector<uint32_t>> input_attachment_to_subpass(pCreateInfo->attachmentCount);
89315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<std::vector<uint32_t>> overlapping_attachments(pCreateInfo->attachmentCount);
89325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Find overlapping attachments
89335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
89345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = i + 1; j < pCreateInfo->attachmentCount; ++j) {
89355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            VkImageView viewi = pFramebufferInfo->pAttachments[i];
89365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            VkImageView viewj = pFramebufferInfo->pAttachments[j];
89375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (viewi == viewj) {
89385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[i].push_back(j);
89395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[j].push_back(i);
89405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                continue;
89415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
89429a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto view_state_i = GetImageViewState(dev_data, viewi);
89439a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto view_state_j = GetImageViewState(dev_data, viewj);
894479fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis            if (!view_state_i || !view_state_j) {
89455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                continue;
89465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
894779fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis            auto view_ci_i = view_state_i->create_info;
894879fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis            auto view_ci_j = view_state_j->create_info;
894979fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis            if (view_ci_i.image == view_ci_j.image && isRegionOverlapping(view_ci_i.subresourceRange, view_ci_j.subresourceRange)) {
89505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[i].push_back(j);
89515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[j].push_back(i);
89525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                continue;
89535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
89549a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto image_data_i = GetImageState(dev_data, view_ci_i.image);
89559a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto image_data_j = GetImageState(dev_data, view_ci_j.image);
89566d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            if (!image_data_i || !image_data_j) {
89575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                continue;
89585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
8959e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis            if (image_data_i->binding.mem == image_data_j->binding.mem &&
8960e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis                isRangeOverlapping(image_data_i->binding.offset, image_data_i->binding.size, image_data_j->binding.offset,
8961e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis                                   image_data_j->binding.size)) {
89625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[i].push_back(j);
89635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[j].push_back(i);
89645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
89655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
89665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
89675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < overlapping_attachments.size(); ++i) {
89685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t attachment = i;
89695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto other_attachment : overlapping_attachments[i]) {
89705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!(pCreateInfo->pAttachments[attachment].flags & VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT)) {
89719bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
8972cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     __LINE__, VALIDATION_ERROR_00324, "DS",
8973cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "Attachment %d aliases attachment %d but doesn't "
8974cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "set VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT. %s",
89759bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                     attachment, other_attachment, validation_error_map[VALIDATION_ERROR_00324]);
89765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
89775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!(pCreateInfo->pAttachments[other_attachment].flags & VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT)) {
89789bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
8979cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     __LINE__, VALIDATION_ERROR_00324, "DS",
8980cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "Attachment %d aliases attachment %d but doesn't "
8981cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "set VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT. %s",
89829bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                     other_attachment, attachment, validation_error_map[VALIDATION_ERROR_00324]);
89835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
89845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
89855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
89865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Find for each attachment the subpasses that use them.
89871c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young    unordered_set<uint32_t> attachmentIndices;
89885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
89895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
89901c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young        attachmentIndices.clear();
89915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
89925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t attachment = subpass.pInputAttachments[j].attachment;
8993cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) continue;
89945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            input_attachment_to_subpass[attachment].push_back(i);
89955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            for (auto overlapping_attachment : overlapping_attachments[attachment]) {
89965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                input_attachment_to_subpass[overlapping_attachment].push_back(i);
89975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
89985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
89995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
90005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t attachment = subpass.pColorAttachments[j].attachment;
9001cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) continue;
90025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            output_attachment_to_subpass[attachment].push_back(i);
90035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            for (auto overlapping_attachment : overlapping_attachments[attachment]) {
90045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                output_attachment_to_subpass[overlapping_attachment].push_back(i);
90055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
90061c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young            attachmentIndices.insert(attachment);
90075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
90085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
90095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t attachment = subpass.pDepthStencilAttachment->attachment;
90105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            output_attachment_to_subpass[attachment].push_back(i);
90115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            for (auto overlapping_attachment : overlapping_attachments[attachment]) {
90125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                output_attachment_to_subpass[overlapping_attachment].push_back(i);
90135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
90141c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young
90151c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young            if (attachmentIndices.count(attachment)) {
90161c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young                skip_call |=
90178860b85a52096f9f9b28616bc37feed505497a54Chris Forbes                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
90188860b85a52096f9f9b28616bc37feed505497a54Chris Forbes                            DRAWSTATE_INVALID_RENDERPASS, "DS",
90198860b85a52096f9f9b28616bc37feed505497a54Chris Forbes                            "Cannot use same attachment (%u) as both color and depth output in same subpass (%u).", attachment, i);
90201c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young            }
90215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
90225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
90235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If there is a dependency needed make sure one exists
90245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
90255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
90265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // If the attachment is an input then all subpasses that output must have a dependency relationship
90275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
902893fe72ec8460857bdb3c101095e6eb96d6171341Chris Forbes            uint32_t attachment = subpass.pInputAttachments[j].attachment;
9029cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) continue;
90308860b85a52096f9f9b28616bc37feed505497a54Chris Forbes            CheckDependencyExists(dev_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip_call);
90315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
90325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // If the attachment is an output then all subpasses that use the attachment must have a dependency relationship
90335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
903493fe72ec8460857bdb3c101095e6eb96d6171341Chris Forbes            uint32_t attachment = subpass.pColorAttachments[j].attachment;
9035cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) continue;
90368860b85a52096f9f9b28616bc37feed505497a54Chris Forbes            CheckDependencyExists(dev_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip_call);
90378860b85a52096f9f9b28616bc37feed505497a54Chris Forbes            CheckDependencyExists(dev_data, i, input_attachment_to_subpass[attachment], subpass_to_node, skip_call);
90385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
90395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
90405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            const uint32_t &attachment = subpass.pDepthStencilAttachment->attachment;
90418860b85a52096f9f9b28616bc37feed505497a54Chris Forbes            CheckDependencyExists(dev_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip_call);
90428860b85a52096f9f9b28616bc37feed505497a54Chris Forbes            CheckDependencyExists(dev_data, i, input_attachment_to_subpass[attachment], subpass_to_node, skip_call);
90435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
90445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
90455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Loop through implicit dependencies, if this pass reads make sure the attachment is preserved for all passes after it was
90465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // written.
90475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
90485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
90495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
90508860b85a52096f9f9b28616bc37feed505497a54Chris Forbes            CheckPreserved(dev_data, pCreateInfo, i, subpass.pInputAttachments[j].attachment, subpass_to_node, 0, skip_call);
90515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
90525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
90535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
90545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
90555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
90568860b85a52096f9f9b28616bc37feed505497a54Chris Forbesstatic bool CreatePassDAG(const layer_data *dev_data, VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
9057e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                          std::vector<DAGNode> &subpass_to_node, std::vector<bool> &has_self_dependency) {
9058e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
90595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
90605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        DAGNode &subpass_node = subpass_to_node[i];
90615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        subpass_node.pass = i;
90625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
90635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->dependencyCount; ++i) {
90645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubpassDependency &dependency = pCreateInfo->pDependencies[i];
906566a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes        if (dependency.srcSubpass == VK_SUBPASS_EXTERNAL || dependency.dstSubpass == VK_SUBPASS_EXTERNAL) {
906666a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes            if (dependency.srcSubpass == dependency.dstSubpass) {
906766a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes                skip_call |=
90688860b85a52096f9f9b28616bc37feed505497a54Chris Forbes                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
906966a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes                            DRAWSTATE_INVALID_RENDERPASS, "DS", "The src and dest subpasses cannot both be external.");
907066a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes            }
907166a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes        } else if (dependency.srcSubpass > dependency.dstSubpass) {
90728860b85a52096f9f9b28616bc37feed505497a54Chris Forbes            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
90735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                 DRAWSTATE_INVALID_RENDERPASS, "DS",
90745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                 "Depedency graph must be specified such that an earlier pass cannot depend on a later pass.");
90755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (dependency.srcSubpass == dependency.dstSubpass) {
90765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            has_self_dependency[dependency.srcSubpass] = true;
90775c6aacf95832467d52b2fde1130b04bef559573aChris Forbes        } else {
90785c6aacf95832467d52b2fde1130b04bef559573aChris Forbes            subpass_to_node[dependency.dstSubpass].prev.push_back(dependency.srcSubpass);
90795c6aacf95832467d52b2fde1130b04bef559573aChris Forbes            subpass_to_node[dependency.srcSubpass].next.push_back(dependency.dstSubpass);
90805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
90815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
90825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
90835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
9084918c283ac4f8c604b79abd0c8b5706d2a7352a34Chris Forbes
908589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo,
9086bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                  const VkAllocationCallbacks *pAllocator, VkShaderModule *pShaderModule) {
908756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
9088e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
9089c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski    spv_result_t spv_valid = SPV_SUCCESS;
9090b1f65702539fd041337fccd493dc6d38dd2a603eChris Forbes
9091e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski    if (!GetDisables(dev_data)->shader_validation) {
9092e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski        // Use SPIRV-Tools validator to try and catch any issues with the module itself
9093e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski        spv_context ctx = spvContextCreate(SPV_ENV_VULKAN_1_0);
9094e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski        spv_const_binary_t binary{pCreateInfo->pCode, pCreateInfo->codeSize / sizeof(uint32_t)};
9095e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski        spv_diagnostic diag = nullptr;
9096b1f65702539fd041337fccd493dc6d38dd2a603eChris Forbes
9097c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski        spv_valid = spvValidate(ctx, &binary, &diag);
9098c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski        if (spv_valid != SPV_SUCCESS) {
90995581a92674a04d2ef49fde417e657f64e3aeed69Mark Lobodzinski            if (!dev_data->device_extensions.nv_glsl_shader_enabled || (pCreateInfo->pCode[0] == spv::MagicNumber)) {
9100c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski                skip_call |= log_msg(dev_data->report_data,
9101c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski                    spv_valid == SPV_WARNING ? VK_DEBUG_REPORT_WARNING_BIT_EXT : VK_DEBUG_REPORT_ERROR_BIT_EXT,
9102c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski                    VkDebugReportObjectTypeEXT(0), 0, __LINE__, SHADER_CHECKER_INCONSISTENT_SPIRV, "SC",
9103c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski                    "SPIR-V module not valid: %s", diag && diag->error ? diag->error : "(no error text)");
9104c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski            }
9105e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski        }
91065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9107e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski        spvDiagnosticDestroy(diag);
9108e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski        spvContextDestroy(ctx);
9109b1f65702539fd041337fccd493dc6d38dd2a603eChris Forbes
9110e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski        if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
9111e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski    }
91125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
91134a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult res = dev_data->dispatch_table.CreateShaderModule(device, pCreateInfo, pAllocator, pShaderModule);
91145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9115e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski    if (res == VK_SUCCESS && !GetDisables(dev_data)->shader_validation) {
9116b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
9117c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski        const auto new_shader_module = (SPV_SUCCESS == spv_valid ? new shader_module(pCreateInfo) : new shader_module());
9118c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski        dev_data->shaderModuleMap[*pShaderModule] = unique_ptr<shader_module>(new_shader_module);
91195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
91205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return res;
91215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
91225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
91234f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinskistatic bool ValidateAttachmentIndex(layer_data *dev_data, uint32_t attachment, uint32_t attachment_count, const char *type) {
91244f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    bool skip_call = false;
91254f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    if (attachment >= attachment_count && attachment != VK_ATTACHMENT_UNUSED) {
91264f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9127e52ca7be57745459d6aa4903a3880fc8eaa9d3dcChris Forbes                             VALIDATION_ERROR_00325, "DS",
9128bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             "CreateRenderPass: %s attachment %d must be less than the total number of attachments %d. %s", type,
9129bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             attachment, attachment_count, validation_error_map[VALIDATION_ERROR_00325]);
91304f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    }
91314f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    return skip_call;
91324f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski}
91334f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
9134bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool IsPowerOfTwo(unsigned x) { return x && !(x & (x - 1)); }
9135805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
91364f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinskistatic bool ValidateRenderpassAttachmentUsage(layer_data *dev_data, const VkRenderPassCreateInfo *pCreateInfo) {
91374f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    bool skip_call = false;
91384f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
91394f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
91404f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        if (subpass.pipelineBindPoint != VK_PIPELINE_BIND_POINT_GRAPHICS) {
91419bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
91429bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                 VALIDATION_ERROR_00347, "DS",
91439bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                 "CreateRenderPass: Pipeline bind point for subpass %d must be VK_PIPELINE_BIND_POINT_GRAPHICS. %s",
91449bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                 i, validation_error_map[VALIDATION_ERROR_00347]);
91454f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
91464f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        for (uint32_t j = 0; j < subpass.preserveAttachmentCount; ++j) {
91474f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            uint32_t attachment = subpass.pPreserveAttachments[j];
91484f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) {
91494f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
91509bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                     __LINE__, VALIDATION_ERROR_00356, "DS",
91519bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                     "CreateRenderPass:  Preserve attachment (%d) must not be VK_ATTACHMENT_UNUSED. %s", j,
91529bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                     validation_error_map[VALIDATION_ERROR_00356]);
91534f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            } else {
91544f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                skip_call |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Preserve");
91554f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            }
91564f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
91576a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes
9158bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto subpass_performs_resolve =
9159bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            subpass.pResolveAttachments &&
9160bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            std::any_of(subpass.pResolveAttachments, subpass.pResolveAttachments + subpass.colorAttachmentCount,
9161bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        [](VkAttachmentReference ref) { return ref.attachment != VK_ATTACHMENT_UNUSED; });
91626a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes
9163805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes        unsigned sample_count = 0;
9164805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
91654f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
91664f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            uint32_t attachment;
91674f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            if (subpass.pResolveAttachments) {
91684f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                attachment = subpass.pResolveAttachments[j].attachment;
91694f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                skip_call |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Resolve");
91706a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes
91716a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes                if (!skip_call && attachment != VK_ATTACHMENT_UNUSED &&
91726a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes                    pCreateInfo->pAttachments[attachment].samples != VK_SAMPLE_COUNT_1_BIT) {
91736a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
91749bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         __LINE__, VALIDATION_ERROR_00352, "DS",
91756a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes                                         "CreateRenderPass:  Subpass %u requests multisample resolve into attachment %u, "
91769bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         "which must have VK_SAMPLE_COUNT_1_BIT but has %s. %s",
91779bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         i, attachment, string_VkSampleCountFlagBits(pCreateInfo->pAttachments[attachment].samples),
91789bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         validation_error_map[VALIDATION_ERROR_00352]);
91796a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes                }
91804f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            }
91814f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            attachment = subpass.pColorAttachments[j].attachment;
91824f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            skip_call |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Color");
91836a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes
9184805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes            if (!skip_call && attachment != VK_ATTACHMENT_UNUSED) {
9185805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes                sample_count |= (unsigned)pCreateInfo->pAttachments[attachment].samples;
9186805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
9187bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (subpass_performs_resolve && pCreateInfo->pAttachments[attachment].samples == VK_SAMPLE_COUNT_1_BIT) {
9188dc7c45f01ae5690f7c969b4760463c1a6bac52d5Chris Forbes                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
91899bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         __LINE__, VALIDATION_ERROR_00351, "DS",
9190dc7c45f01ae5690f7c969b4760463c1a6bac52d5Chris Forbes                                         "CreateRenderPass:  Subpass %u requests multisample resolve from attachment %u "
91919bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         "which has VK_SAMPLE_COUNT_1_BIT. %s",
91929bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         i, attachment, validation_error_map[VALIDATION_ERROR_00351]);
9193dc7c45f01ae5690f7c969b4760463c1a6bac52d5Chris Forbes                }
91946a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes            }
91954f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
9196dc7c45f01ae5690f7c969b4760463c1a6bac52d5Chris Forbes
91974f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
91984f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            uint32_t attachment = subpass.pDepthStencilAttachment->attachment;
91994f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            skip_call |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Depth stencil");
9200805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
9201805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes            if (!skip_call && attachment != VK_ATTACHMENT_UNUSED) {
9202805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes                sample_count |= (unsigned)pCreateInfo->pAttachments[attachment].samples;
9203805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes            }
92044f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
9205dc7c45f01ae5690f7c969b4760463c1a6bac52d5Chris Forbes
92064f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
92074f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            uint32_t attachment = subpass.pInputAttachments[j].attachment;
92084f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            skip_call |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Input");
92094f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
9210805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
9211805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes        if (sample_count && !IsPowerOfTwo(sample_count)) {
92129bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
9213cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 VALIDATION_ERROR_00337, "DS",
9214cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "CreateRenderPass:  Subpass %u attempts to render to "
9215cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "attachments with inconsistent sample counts. %s",
92169bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                 i, validation_error_map[VALIDATION_ERROR_00337]);
9217805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes        }
92184f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    }
92194f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    return skip_call;
92204f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski}
92214f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
922289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
92234f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                                                const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) {
9224e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
922556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
92264f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
92274f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    std::unique_lock<std::mutex> lock(global_lock);
92284f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    // TODO: As part of wrapping up the mem_tracker/core_validation merge the following routine should be consolidated with
92294f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    //       ValidateLayouts.
92304f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    skip_call |= ValidateRenderpassAttachmentUsage(dev_data, pCreateInfo);
9231208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->dependencyCount; ++i) {
9232208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip_call |= ValidateStageMaskGsTsEnables(dev_data, pCreateInfo->pDependencies[i].srcStageMask, "vkCreateRenderPass()",
9233208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                                                  VALIDATION_ERROR_00368, VALIDATION_ERROR_00370);
9234208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip_call |= ValidateStageMaskGsTsEnables(dev_data, pCreateInfo->pDependencies[i].dstStageMask, "vkCreateRenderPass()",
9235208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                                                  VALIDATION_ERROR_00369, VALIDATION_ERROR_00371);
9236208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    }
9237ab38df28c5ae1816c5fa33c0c7840c6950e83f0dChris Forbes    if (!skip_call) {
9238ab38df28c5ae1816c5fa33c0c7840c6950e83f0dChris Forbes        skip_call |= ValidateLayouts(dev_data, device, pCreateInfo);
9239ab38df28c5ae1816c5fa33c0c7840c6950e83f0dChris Forbes    }
9240ff6101de02d1677fb54962e2ff57875e76898e26Chris Forbes    lock.unlock();
92414f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
92424f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    if (skip_call) {
92434f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        return VK_ERROR_VALIDATION_FAILED_EXT;
92444f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    }
92454f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
92464a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateRenderPass(device, pCreateInfo, pAllocator, pRenderPass);
9247ff6101de02d1677fb54962e2ff57875e76898e26Chris Forbes
92485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
92494f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        lock.lock();
92504f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
92514f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        std::vector<bool> has_self_dependency(pCreateInfo->subpassCount);
92524f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        std::vector<DAGNode> subpass_to_node(pCreateInfo->subpassCount);
92534f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        skip_call |= CreatePassDAG(dev_data, device, pCreateInfo, subpass_to_node, has_self_dependency);
92544f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
9255127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis        auto render_pass = unique_ptr<RENDER_PASS_STATE>(new RENDER_PASS_STATE(pCreateInfo));
925698cddf7090b5d5dcc382045867753ef703d1c3d3Chris Forbes        render_pass->renderPass = *pRenderPass;
9257cf2686cdbb12af8a29ca598c126b5e37215f0ef7Chris Forbes        render_pass->hasSelfDependency = has_self_dependency;
9258cf2686cdbb12af8a29ca598c126b5e37215f0ef7Chris Forbes        render_pass->subpassToNode = subpass_to_node;
9259db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes
926087e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis        // TODO: Maybe fill list and then copy instead of locking
9261cf2686cdbb12af8a29ca598c126b5e37215f0ef7Chris Forbes        std::unordered_map<uint32_t, bool> &attachment_first_read = render_pass->attachment_first_read;
92626600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski        std::unordered_map<uint32_t, VkImageLayout> &attachment_first_layout = render_pass->attachment_first_layout;
926387e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis        for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
926487e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis            const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
926587e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis            for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
92664f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                uint32_t attachment = subpass.pColorAttachments[j].attachment;
92674f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                if (!attachment_first_read.count(attachment)) {
92684f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                    attachment_first_read.insert(std::make_pair(attachment, false));
92694f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                    attachment_first_layout.insert(std::make_pair(attachment, subpass.pColorAttachments[j].layout));
92700d615f0a5724edac98475366cf3e486dccc1f2d6Michael Lentine                }
927187e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis            }
927287e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis            if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
927387e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis                uint32_t attachment = subpass.pDepthStencilAttachment->attachment;
92744f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                if (!attachment_first_read.count(attachment)) {
92754f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                    attachment_first_read.insert(std::make_pair(attachment, false));
92764f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                    attachment_first_layout.insert(std::make_pair(attachment, subpass.pDepthStencilAttachment->layout));
927724991fb692f7e2d457da50d50c40f2705591300cMichael Lentine                }
927887e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis            }
9279a5ce96d7c88653668a2b33a6b72bd3cb16d73f48Michael Lentine            for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
9280a5ce96d7c88653668a2b33a6b72bd3cb16d73f48Michael Lentine                uint32_t attachment = subpass.pInputAttachments[j].attachment;
92814f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                if (!attachment_first_read.count(attachment)) {
92824f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                    attachment_first_read.insert(std::make_pair(attachment, true));
92834f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                    attachment_first_layout.insert(std::make_pair(attachment, subpass.pInputAttachments[j].layout));
928424991fb692f7e2d457da50d50c40f2705591300cMichael Lentine                }
9285a5ce96d7c88653668a2b33a6b72bd3cb16d73f48Michael Lentine            }
928687e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis        }
9287db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes
9288fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes        dev_data->renderPassMap[*pRenderPass] = std::move(render_pass);
92895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
92905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
92915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
92924f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
92939bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardtstatic bool validatePrimaryCommandBuffer(const layer_data *dev_data, const GLOBAL_CB_NODE *pCB, const std::string &cmd_name,
92949bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         UNIQUE_VALIDATION_ERROR_CODE error_code) {
9295e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
92965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
92978860b85a52096f9f9b28616bc37feed505497a54Chris Forbes        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
92989bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             error_code, "DS", "Cannot execute command %s on a secondary command buffer. %s", cmd_name.c_str(),
92999bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             validation_error_map[error_code]);
93005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
93015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
93025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
93035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
93048860b85a52096f9f9b28616bc37feed505497a54Chris Forbesstatic bool VerifyRenderAreaBounds(const layer_data *dev_data, const VkRenderPassBeginInfo *pRenderPassBegin) {
9305885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine    bool skip_call = false;
9306c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    const safe_VkFramebufferCreateInfo *pFramebufferInfo =
93079a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        &GetFramebufferState(dev_data, pRenderPassBegin->framebuffer)->createInfo;
9308885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine    if (pRenderPassBegin->renderArea.offset.x < 0 ||
9309885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine        (pRenderPassBegin->renderArea.offset.x + pRenderPassBegin->renderArea.extent.width) > pFramebufferInfo->width ||
9310885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine        pRenderPassBegin->renderArea.offset.y < 0 ||
9311885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine        (pRenderPassBegin->renderArea.offset.y + pRenderPassBegin->renderArea.extent.height) > pFramebufferInfo->height) {
9312885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine        skip_call |= static_cast<bool>(log_msg(
93138860b85a52096f9f9b28616bc37feed505497a54Chris Forbes            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9314885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            DRAWSTATE_INVALID_RENDER_AREA, "CORE",
9315885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            "Cannot execute a render pass with renderArea not within the bound of the "
9316885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            "framebuffer. RenderArea: x %d, y %d, width %d, height %d. Framebuffer: width %d, "
9317885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            "height %d.",
9318885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            pRenderPassBegin->renderArea.offset.x, pRenderPassBegin->renderArea.offset.y, pRenderPassBegin->renderArea.extent.width,
9319885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            pRenderPassBegin->renderArea.extent.height, pFramebufferInfo->width, pFramebufferInfo->height));
9320885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine    }
9321885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine    return skip_call;
9322885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine}
9323885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine
93241a65650f856376768d7b03ea2d080aaff87cacfdMark 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
93251a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski// [load|store]Op flag must be checked
93261a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski// TODO: The memory valid flag in DEVICE_MEM_INFO should probably be split to track the validity of stencil memory separately.
9327cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskitemplate <typename T>
9328cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskistatic bool FormatSpecificLoadAndStoreOpSettings(VkFormat format, T color_depth_op, T stencil_op, T op) {
9329a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski    if (color_depth_op != op && stencil_op != op) {
9330a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski        return false;
9331a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski    }
93321a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski    bool check_color_depth_load_op = !vk_format_is_stencil_only(format);
93331a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski    bool check_stencil_load_op = vk_format_is_depth_and_stencil(format) || !check_color_depth_load_op;
9334a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski
9335a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski    return (((check_color_depth_load_op == true) && (color_depth_op == op)) ||
9336a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski            ((check_stencil_load_op == true) && (stencil_op == op)));
93371a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski}
93381a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski
9339bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
9340bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              VkSubpassContents contents) {
934183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
934256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
9343b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
93449a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *cb_node = GetCBNode(dev_data, commandBuffer);
93459a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto render_pass_state = pRenderPassBegin ? GetRenderPassState(dev_data, pRenderPassBegin->renderPass) : nullptr;
93469a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto framebuffer = pRenderPassBegin ? GetFramebufferState(dev_data, pRenderPassBegin->framebuffer) : nullptr;
9347f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis    if (cb_node) {
9348308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski        if (render_pass_state) {
9349cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            uint32_t clear_op_size = 0;  // Make sure pClearValues is at least as large as last LOAD_OP_CLEAR
9350f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->activeFramebuffer = pRenderPassBegin->framebuffer;
9351308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski            for (uint32_t i = 0; i < render_pass_state->createInfo.attachmentCount; ++i) {
9352f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes                MT_FB_ATTACHMENT_INFO &fb_info = framebuffer->attachments[i];
9353308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski                auto pAttachment = &render_pass_state->createInfo.pAttachments[i];
9354bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->loadOp, pAttachment->stencilLoadOp,
93551a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski                                                         VK_ATTACHMENT_LOAD_OP_CLEAR)) {
935692bc0680357019834b7529148ab6d73353ce02c7Mark Lobodzinski                    clear_op_size = static_cast<uint32_t>(i) + 1;
935716387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    std::function<bool()> function = [=]() {
93589a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        SetImageMemoryValid(dev_data, GetImageState(dev_data, fb_info.image), true);
935916387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                        return false;
936016387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    };
9361f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                    cb_node->validate_functions.push_back(function);
9362db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes                } else if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->loadOp,
9363bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                pAttachment->stencilLoadOp, VK_ATTACHMENT_LOAD_OP_DONT_CARE)) {
936416387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    std::function<bool()> function = [=]() {
93659a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        SetImageMemoryValid(dev_data, GetImageState(dev_data, fb_info.image), false);
936616387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                        return false;
936716387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    };
9368f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                    cb_node->validate_functions.push_back(function);
9369db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes                } else if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->loadOp,
9370bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                pAttachment->stencilLoadOp, VK_ATTACHMENT_LOAD_OP_LOAD)) {
937116387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    std::function<bool()> function = [=]() {
93729a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        return ValidateImageMemoryIsValid(dev_data, GetImageState(dev_data, fb_info.image),
9373f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis                                                          "vkCmdBeginRenderPass()");
937416387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    };
9375f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                    cb_node->validate_functions.push_back(function);
937616387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                }
9377308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski                if (render_pass_state->attachment_first_read[i]) {
937816387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    std::function<bool()> function = [=]() {
93799a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        return ValidateImageMemoryIsValid(dev_data, GetImageState(dev_data, fb_info.image),
9380f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis                                                          "vkCmdBeginRenderPass()");
938116387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    };
9382f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                    cb_node->validate_functions.push_back(function);
93835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
93845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
93856de3c6ffa0819ee37cd5cecee918b062145e2ff1Tobin Ehlis            if (clear_op_size > pRenderPassBegin->clearValueCount) {
9386369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                skip_call |= log_msg(
9387369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
9388308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski                    reinterpret_cast<uint64_t &>(render_pass_state->renderPass), __LINE__, VALIDATION_ERROR_00442, "DS",
9389bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "In vkCmdBeginRenderPass() the VkRenderPassBeginInfo struct has a clearValueCount of %u but there must "
9390bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "be at least %u entries in pClearValues array to account for the highest index attachment in renderPass "
9391cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "0x%" PRIx64
9392cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    " that uses VK_ATTACHMENT_LOAD_OP_CLEAR is %u. Note that the pClearValues array "
9393bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "is indexed by attachment number so even if some pClearValues entries between 0 and %u correspond to "
9394bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "attachments that aren't cleared they will be ignored. %s",
9395308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski                    pRenderPassBegin->clearValueCount, clear_op_size, reinterpret_cast<uint64_t &>(render_pass_state->renderPass),
93965504d0369cbc97ad7c221eddbad439bfb83e3fb6Mark Lobodzinski                    clear_op_size, clear_op_size - 1, validation_error_map[VALIDATION_ERROR_00442]);
9397369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan            }
9398369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan            if (clear_op_size < pRenderPassBegin->clearValueCount) {
9399369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                skip_call |= log_msg(
9400369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                    dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
9401308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski                    reinterpret_cast<uint64_t &>(render_pass_state->renderPass), __LINE__,
9402308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski                    DRAWSTATE_RENDERPASS_TOO_MANY_CLEAR_VALUES, "DS",
9403369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                    "In vkCmdBeginRenderPass() the VkRenderPassBeginInfo struct has a clearValueCount of %u but only first %u "
94047bab3d8f0599701f6e26a2d76314588486ae99c9Mark Lobodzinski                    "entries in pClearValues array are used. The highest index of any attachment in renderPass 0x%" PRIx64
9405369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                    " that uses VK_ATTACHMENT_LOAD_OP_CLEAR is %u - other pClearValues are ignored.",
9406308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski                    pRenderPassBegin->clearValueCount, clear_op_size, reinterpret_cast<uint64_t &>(render_pass_state->renderPass),
94077bab3d8f0599701f6e26a2d76314588486ae99c9Mark Lobodzinski                    clear_op_size - 1);
94083d71bca42a843966040d6ada9c029e0ec9f35ca6Tobin Ehlis            }
940983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= VerifyRenderAreaBounds(dev_data, pRenderPassBegin);
941055867dbad6ae423b3bd78c15f6771031a710b5adMark Lobodzinski            skip_call |= VerifyFramebufferAndRenderPassLayouts(dev_data, cb_node, pRenderPassBegin,
94119a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                                                               GetFramebufferState(dev_data, pRenderPassBegin->framebuffer));
9412ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen            skip_call |= insideRenderPass(dev_data, cb_node, "vkCmdBeginRenderPass()", VALIDATION_ERROR_00440);
9413308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski            skip_call |= ValidateDependencies(dev_data, framebuffer, render_pass_state);
94149bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt            skip_call |= validatePrimaryCommandBuffer(dev_data, cb_node, "vkCmdBeginRenderPass", VALIDATION_ERROR_00441);
941529f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis            skip_call |= ValidateCmd(dev_data, cb_node, CMD_BEGINRENDERPASS, "vkCmdBeginRenderPass()");
94161ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis            UpdateCmdBufferLastCmd(cb_node, CMD_BEGINRENDERPASS);
9417308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski            cb_node->activeRenderPass = render_pass_state;
94185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // This is a shallow copy as that is all that is needed for now
9419f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->activeRenderPassBeginInfo = *pRenderPassBegin;
9420f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->activeSubpass = 0;
9421f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->activeSubpassContents = contents;
9422f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->framebuffers.insert(pRenderPassBegin->framebuffer);
9423883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis            // Connect this framebuffer and its children to this cmdBuffer
9424883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis            AddFramebufferBinding(dev_data, cb_node, framebuffer);
9425ea0f86230ff5c52f805ac831a1ed5a92bd123368Chris Forbes            // transition attachments to the correct layouts for the first subpass
942655867dbad6ae423b3bd78c15f6771031a710b5adMark Lobodzinski            TransitionSubpassLayouts(dev_data, cb_node, &cb_node->activeRenderPassBeginInfo, cb_node->activeSubpass, framebuffer);
94275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
94285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9429b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
943083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (!skip_call) {
94314a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdBeginRenderPass(commandBuffer, pRenderPassBegin, contents);
94325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
94335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
94345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
943589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents) {
943683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
943756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
9438b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
94399a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
94405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
94419bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt        skip_call |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdNextSubpass", VALIDATION_ERROR_00459);
944229f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_NEXTSUBPASS, "vkCmdNextSubpass()");
94431ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_NEXTSUBPASS);
9444ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen        skip_call |= outsideRenderPass(dev_data, pCB, "vkCmdNextSubpass()", VALIDATION_ERROR_00458);
944580281691386b37385846f21b38e8c9d4b12cc74eChris Forbes
9446fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes        auto subpassCount = pCB->activeRenderPass->createInfo.subpassCount;
944780281691386b37385846f21b38e8c9d4b12cc74eChris Forbes        if (pCB->activeSubpass == subpassCount - 1) {
94489bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt            skip_call |= log_msg(
94499bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
94509bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                reinterpret_cast<uint64_t>(commandBuffer), __LINE__, VALIDATION_ERROR_00453, "DS",
94519bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                "vkCmdNextSubpass(): Attempted to advance beyond final subpass. %s", validation_error_map[VALIDATION_ERROR_00453]);
945280281691386b37385846f21b38e8c9d4b12cc74eChris Forbes        }
94535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9454b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
945596ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes
9456cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return;
945796ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes
94584a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.CmdNextSubpass(commandBuffer, contents);
945996ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes
946096ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes    if (pCB) {
9461bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        lock.lock();
9462bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pCB->activeSubpass++;
9463bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pCB->activeSubpassContents = contents;
946455867dbad6ae423b3bd78c15f6771031a710b5adMark Lobodzinski        TransitionSubpassLayouts(dev_data, pCB, &pCB->activeRenderPassBeginInfo, pCB->activeSubpass,
94659a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                                 GetFramebufferState(dev_data, pCB->activeRenderPassBeginInfo.framebuffer));
946696ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes    }
94675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
94685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
946989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdEndRenderPass(VkCommandBuffer commandBuffer) {
947083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
947156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
9472b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
94739a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pCB = GetCBNode(dev_data, commandBuffer);
947455867dbad6ae423b3bd78c15f6771031a710b5adMark Lobodzinski    FRAMEBUFFER_STATE *framebuffer = NULL;
947558c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes    if (pCB) {
9476127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis        RENDER_PASS_STATE *rp_state = pCB->activeRenderPass;
94779a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        framebuffer = GetFramebufferState(dev_data, pCB->activeFramebuffer);
9478127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis        if (rp_state) {
9479127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis            if (pCB->activeSubpass != rp_state->createInfo.subpassCount - 1) {
94809bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                skip_call |= log_msg(
94819bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
94829bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                    reinterpret_cast<uint64_t>(commandBuffer), __LINE__, VALIDATION_ERROR_00460, "DS",
94839bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                    "vkCmdEndRenderPass(): Called before reaching final subpass. %s", validation_error_map[VALIDATION_ERROR_00460]);
948402a3382f28fc7c6ec6018165be88aa6fc4f05c9eChris Forbes            }
948502a3382f28fc7c6ec6018165be88aa6fc4f05c9eChris Forbes
9486127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis            for (size_t i = 0; i < rp_state->createInfo.attachmentCount; ++i) {
9487e3ad4b1284408353cc56a04951c1df1f35a636ceChris Forbes                MT_FB_ATTACHMENT_INFO &fb_info = framebuffer->attachments[i];
9488127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                auto pAttachment = &rp_state->createInfo.pAttachments[i];
9489bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->storeOp, pAttachment->stencilStoreOp,
9490bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                         VK_ATTACHMENT_STORE_OP_STORE)) {
949158c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    std::function<bool()> function = [=]() {
94929a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        SetImageMemoryValid(dev_data, GetImageState(dev_data, fb_info.image), true);
949358c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                        return false;
949458c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    };
949558c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    pCB->validate_functions.push_back(function);
9496db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes                } else if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->storeOp,
9497bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                pAttachment->stencilStoreOp, VK_ATTACHMENT_STORE_OP_DONT_CARE)) {
949858c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    std::function<bool()> function = [=]() {
94999a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        SetImageMemoryValid(dev_data, GetImageState(dev_data, fb_info.image), false);
950058c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                        return false;
950158c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    };
950258c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    pCB->validate_functions.push_back(function);
95035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
95045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
95055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
9506ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen        skip_call |= outsideRenderPass(dev_data, pCB, "vkCmdEndRenderpass()", VALIDATION_ERROR_00464);
95079bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt        skip_call |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdEndRenderPass", VALIDATION_ERROR_00465);
950829f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_ENDRENDERPASS, "vkCmdEndRenderPass()");
95091ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_ENDRENDERPASS);
95100e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes    }
95110e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes    lock.unlock();
95120e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes
9513cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return;
95140e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes
95154a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.CmdEndRenderPass(commandBuffer);
95160e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes
95170e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes    if (pCB) {
95180e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes        lock.lock();
951955867dbad6ae423b3bd78c15f6771031a710b5adMark Lobodzinski        TransitionFinalSubpassLayouts(dev_data, pCB, &pCB->activeRenderPassBeginInfo, framebuffer);
952058c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes        pCB->activeRenderPass = nullptr;
952158c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes        pCB->activeSubpass = 0;
952258c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes        pCB->activeFramebuffer = VK_NULL_HANDLE;
95235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
95245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
95255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9526a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlisstatic bool logInvalidAttachmentMessage(layer_data *dev_data, VkCommandBuffer secondaryBuffer, uint32_t primaryAttach,
9527a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                        uint32_t secondaryAttach, const char *msg) {
95285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9529cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                   VALIDATION_ERROR_02059, "DS", "vkCmdExecuteCommands() called w/ invalid Secondary Cmd Buffer 0x%" PRIx64
9530cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                 " which has a render pass "
9531cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                 "that is not compatible with the Primary Cmd Buffer current render pass. "
9532cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                 "Attachment %u is not compatible with %u: %s. %s",
95339bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                   reinterpret_cast<uint64_t &>(secondaryBuffer), primaryAttach, secondaryAttach, msg,
95349bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                   validation_error_map[VALIDATION_ERROR_02059]);
95355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
95365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9537a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlisstatic bool validateAttachmentCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer,
9538a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                            VkRenderPassCreateInfo const *primaryPassCI, uint32_t primaryAttach,
9539a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                            VkCommandBuffer secondaryBuffer, VkRenderPassCreateInfo const *secondaryPassCI,
9540e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                                            uint32_t secondaryAttach, bool is_multi) {
95415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool skip_call = false;
9542a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (primaryPassCI->attachmentCount <= primaryAttach) {
95435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        primaryAttach = VK_ATTACHMENT_UNUSED;
95445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9545a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (secondaryPassCI->attachmentCount <= secondaryAttach) {
95465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        secondaryAttach = VK_ATTACHMENT_UNUSED;
95475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
95485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (primaryAttach == VK_ATTACHMENT_UNUSED && secondaryAttach == VK_ATTACHMENT_UNUSED) {
95495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return skip_call;
95505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
95515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (primaryAttach == VK_ATTACHMENT_UNUSED) {
9552a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach,
9553a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                                 "The first is unused while the second is not.");
95545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return skip_call;
95555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
95565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (secondaryAttach == VK_ATTACHMENT_UNUSED) {
9557a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach,
9558a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                                 "The second is unused while the first is not.");
95595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return skip_call;
95605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9561a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (primaryPassCI->pAttachments[primaryAttach].format != secondaryPassCI->pAttachments[secondaryAttach].format) {
9562a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        skip_call |=
9563a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis            logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach, "They have different formats.");
95645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9565a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (primaryPassCI->pAttachments[primaryAttach].samples != secondaryPassCI->pAttachments[secondaryAttach].samples) {
9566a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        skip_call |=
9567a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis            logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach, "They have different samples.");
95685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9569a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (is_multi && primaryPassCI->pAttachments[primaryAttach].flags != secondaryPassCI->pAttachments[secondaryAttach].flags) {
9570a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        skip_call |=
9571a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis            logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach, "They have different flags.");
95725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
95735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
95745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
95755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9576a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlisstatic bool validateSubpassCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer,
9577a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                         VkRenderPassCreateInfo const *primaryPassCI, VkCommandBuffer secondaryBuffer,
9578a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                         VkRenderPassCreateInfo const *secondaryPassCI, const int subpass, bool is_multi) {
95795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool skip_call = false;
9580a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    const VkSubpassDescription &primary_desc = primaryPassCI->pSubpasses[subpass];
9581a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    const VkSubpassDescription &secondary_desc = secondaryPassCI->pSubpasses[subpass];
95825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t maxInputAttachmentCount = std::max(primary_desc.inputAttachmentCount, secondary_desc.inputAttachmentCount);
95835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < maxInputAttachmentCount; ++i) {
95845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primary_input_attach = VK_ATTACHMENT_UNUSED, secondary_input_attach = VK_ATTACHMENT_UNUSED;
95855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < primary_desc.inputAttachmentCount) {
95865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            primary_input_attach = primary_desc.pInputAttachments[i].attachment;
95875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
95885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < secondary_desc.inputAttachmentCount) {
95895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            secondary_input_attach = secondary_desc.pInputAttachments[i].attachment;
95905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
9591a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPassCI, primary_input_attach, secondaryBuffer,
9592a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                                     secondaryPassCI, secondary_input_attach, is_multi);
95935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
95945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t maxColorAttachmentCount = std::max(primary_desc.colorAttachmentCount, secondary_desc.colorAttachmentCount);
95955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < maxColorAttachmentCount; ++i) {
95965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primary_color_attach = VK_ATTACHMENT_UNUSED, secondary_color_attach = VK_ATTACHMENT_UNUSED;
95975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < primary_desc.colorAttachmentCount) {
95985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            primary_color_attach = primary_desc.pColorAttachments[i].attachment;
95995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
96005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < secondary_desc.colorAttachmentCount) {
96015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            secondary_color_attach = secondary_desc.pColorAttachments[i].attachment;
96025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
9603a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPassCI, primary_color_attach, secondaryBuffer,
9604a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                                     secondaryPassCI, secondary_color_attach, is_multi);
96055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primary_resolve_attach = VK_ATTACHMENT_UNUSED, secondary_resolve_attach = VK_ATTACHMENT_UNUSED;
96065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < primary_desc.colorAttachmentCount && primary_desc.pResolveAttachments) {
96075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            primary_resolve_attach = primary_desc.pResolveAttachments[i].attachment;
96085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
96095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < secondary_desc.colorAttachmentCount && secondary_desc.pResolveAttachments) {
96105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            secondary_resolve_attach = secondary_desc.pResolveAttachments[i].attachment;
96115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
9612a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPassCI, primary_resolve_attach,
9613a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                                     secondaryBuffer, secondaryPassCI, secondary_resolve_attach, is_multi);
96145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
96155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t primary_depthstencil_attach = VK_ATTACHMENT_UNUSED, secondary_depthstencil_attach = VK_ATTACHMENT_UNUSED;
96165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (primary_desc.pDepthStencilAttachment) {
96175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        primary_depthstencil_attach = primary_desc.pDepthStencilAttachment[0].attachment;
96185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
96195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (secondary_desc.pDepthStencilAttachment) {
96205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        secondary_depthstencil_attach = secondary_desc.pDepthStencilAttachment[0].attachment;
96215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9622a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPassCI, primary_depthstencil_attach,
9623a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                                 secondaryBuffer, secondaryPassCI, secondary_depthstencil_attach, is_multi);
96245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
96255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
96265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9627a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis// Verify that given renderPass CreateInfo for primary and secondary command buffers are compatible.
9628a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis//  This function deals directly with the CreateInfo, there are overloaded versions below that can take the renderPass handle and
9629a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis//  will then feed into this function
9630a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlisstatic bool validateRenderPassCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer,
9631a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                            VkRenderPassCreateInfo const *primaryPassCI, VkCommandBuffer secondaryBuffer,
9632a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                            VkRenderPassCreateInfo const *secondaryPassCI) {
96335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool skip_call = false;
9634a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis
9635a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (primaryPassCI->subpassCount != secondaryPassCI->subpassCount) {
96365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
96375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                             DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
9638a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                             "vkCmdExecuteCommands() called w/ invalid secondary Cmd Buffer 0x%" PRIx64
9639a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                             " that has a subpassCount of %u that is incompatible with the primary Cmd Buffer 0x%" PRIx64
9640a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                             " that has a subpassCount of %u.",
9641a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                             reinterpret_cast<uint64_t &>(secondaryBuffer), secondaryPassCI->subpassCount,
9642a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                             reinterpret_cast<uint64_t &>(primaryBuffer), primaryPassCI->subpassCount);
9643a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    } else {
9644a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        for (uint32_t i = 0; i < primaryPassCI->subpassCount; ++i) {
9645a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis            skip_call |= validateSubpassCompatibility(dev_data, primaryBuffer, primaryPassCI, secondaryBuffer, secondaryPassCI, i,
9646a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                                      primaryPassCI->subpassCount > 1);
9647a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        }
96485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
96495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
96505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
96515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9652e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool validateFramebuffer(layer_data *dev_data, VkCommandBuffer primaryBuffer, const GLOBAL_CB_NODE *pCB,
9653e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                                VkCommandBuffer secondaryBuffer, const GLOBAL_CB_NODE *pSubCB) {
96545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool skip_call = false;
96555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (!pSubCB->beginInfo.pInheritanceInfo) {
96565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return skip_call;
96575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9658c5b97dda856ff837638b3ebb7e231d5507c495a3Chris Forbes    VkFramebuffer primary_fb = pCB->activeFramebuffer;
96595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkFramebuffer secondary_fb = pSubCB->beginInfo.pInheritanceInfo->framebuffer;
96605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (secondary_fb != VK_NULL_HANDLE) {
96615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (primary_fb != secondary_fb) {
96629bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt            skip_call |= log_msg(
96639bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
96649bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                VALIDATION_ERROR_02060, "DS",
96659bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                "vkCmdExecuteCommands() called w/ invalid secondary command buffer 0x%" PRIx64 " which has a framebuffer 0x%" PRIx64
96669bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                " that is not the same as the primary command buffer's current active framebuffer 0x%" PRIx64 ". %s",
96679bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                reinterpret_cast<uint64_t &>(secondaryBuffer), reinterpret_cast<uint64_t &>(secondary_fb),
96689bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                reinterpret_cast<uint64_t &>(primary_fb), validation_error_map[VALIDATION_ERROR_02060]);
96695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
96709a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto fb = GetFramebufferState(dev_data, secondary_fb);
9671e3ad4b1284408353cc56a04951c1df1f35a636ceChris Forbes        if (!fb) {
9672bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9673bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
9674bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 "vkCmdExecuteCommands() called w/ invalid Cmd Buffer 0x%p "
9675bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 "which has invalid framebuffer 0x%" PRIx64 ".",
9676bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 (void *)secondaryBuffer, (uint64_t)(secondary_fb));
96775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return skip_call;
96785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
96799a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto cb_renderpass = GetRenderPassState(dev_data, pSubCB->beginInfo.pInheritanceInfo->renderPass);
9680a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        if (cb_renderpass->renderPass != fb->createInfo.renderPass) {
9681a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis            skip_call |= validateRenderPassCompatibility(dev_data, secondaryBuffer, fb->renderPassCreateInfo.ptr(), secondaryBuffer,
9682fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes                                                         cb_renderpass->createInfo.ptr());
9683a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        }
96845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
96855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
96865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
96875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9688e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool validateSecondaryCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB, GLOBAL_CB_NODE *pSubCB) {
968983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
96905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_set<int> activeTypes;
96915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto queryObject : pCB->activeQueries) {
96925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto queryPoolData = dev_data->queryPoolMap.find(queryObject.pool);
96935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (queryPoolData != dev_data->queryPoolMap.end()) {
96945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (queryPoolData->second.createInfo.queryType == VK_QUERY_TYPE_PIPELINE_STATISTICS &&
96955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pSubCB->beginInfo.pInheritanceInfo) {
96965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                VkQueryPipelineStatisticFlags cmdBufStatistics = pSubCB->beginInfo.pInheritanceInfo->pipelineStatistics;
96975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if ((cmdBufStatistics & queryPoolData->second.createInfo.pipelineStatistics) != cmdBufStatistics) {
9698cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
9699cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         __LINE__, VALIDATION_ERROR_02065, "DS",
9700cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         "vkCmdExecuteCommands() called w/ invalid Cmd Buffer 0x%p "
9701cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         "which has invalid active query pool 0x%" PRIx64
9702cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         ". Pipeline statistics is being queried so the command "
9703cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         "buffer must have all bits set on the queryPool. %s",
9704cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         pCB->commandBuffer, reinterpret_cast<const uint64_t &>(queryPoolData->first),
9705cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         validation_error_map[VALIDATION_ERROR_02065]);
97065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
97075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
97085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            activeTypes.insert(queryPoolData->second.createInfo.queryType);
97095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
97105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
97115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto queryObject : pSubCB->startedQueries) {
97125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto queryPoolData = dev_data->queryPoolMap.find(queryObject.pool);
97135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (queryPoolData != dev_data->queryPoolMap.end() && activeTypes.count(queryPoolData->second.createInfo.queryType)) {
9714cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9715cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
9716cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "vkCmdExecuteCommands() called w/ invalid Cmd Buffer 0x%p "
9717cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "which has invalid active query pool 0x%" PRIx64
9718cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "of type %d but a query of that type has been started on "
9719cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "secondary Cmd Buffer 0x%p.",
9720cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 pCB->commandBuffer, reinterpret_cast<const uint64_t &>(queryPoolData->first),
9721cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 queryPoolData->second.createInfo.queryType, pSubCB->commandBuffer);
97225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
97235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
97247bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
97259a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto primary_pool = GetCommandPoolNode(dev_data, pCB->createInfo.commandPool);
97269a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto secondary_pool = GetCommandPoolNode(dev_data, pSubCB->createInfo.commandPool);
97277bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski    if (primary_pool && secondary_pool && (primary_pool->queueFamilyIndex != secondary_pool->queueFamilyIndex)) {
9728226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis        skip_call |=
9729226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9730226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    reinterpret_cast<uint64_t>(pSubCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_QUEUE_FAMILY, "DS",
9731226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    "vkCmdExecuteCommands(): Primary command buffer 0x%p"
9732226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    " created in queue family %d has secondary command buffer 0x%p created in queue family %d.",
9733226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    pCB->commandBuffer, primary_pool->queueFamilyIndex, pSubCB->commandBuffer, secondary_pool->queueFamilyIndex);
97347bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski    }
97357bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
973683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
97375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
97385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9739bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBuffersCount,
9740bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              const VkCommandBuffer *pCommandBuffers) {
974183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
974256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
9743b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
97449a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
97455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
97465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        GLOBAL_CB_NODE *pSubCB = NULL;
97475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < commandBuffersCount; i++) {
97489a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            pSubCB = GetCBNode(dev_data, pCommandBuffers[i]);
97490a8b955c23012196339f3c10ffedc631ea0f7c58Tobin Ehlis            assert(pSubCB);
97500a8b955c23012196339f3c10ffedc631ea0f7c58Tobin Ehlis            if (VK_COMMAND_BUFFER_LEVEL_PRIMARY == pSubCB->createInfo.level) {
975183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
97524b6738a6adb4e813d66234defee5d18b7c84340dMike Weiblen                                     __LINE__, VALIDATION_ERROR_00153, "DS",
975383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                     "vkCmdExecuteCommands() called w/ Primary Cmd Buffer 0x%p in element %u of pCommandBuffers "
97544b6738a6adb4e813d66234defee5d18b7c84340dMike Weiblen                                     "array. All cmd buffers in pCommandBuffers array must be secondary. %s",
9755226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                     pCommandBuffers[i], i, validation_error_map[VALIDATION_ERROR_00153]);
9756cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else if (pCB->activeRenderPass) {  // Secondary CB w/i RenderPass must have *CONTINUE_BIT set
97579a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto secondary_rp_state = GetRenderPassState(dev_data, pSubCB->beginInfo.pInheritanceInfo->renderPass);
97585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (!(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
975983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |= log_msg(
97605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
97614b6738a6adb4e813d66234defee5d18b7c84340dMike Weiblen                        (uint64_t)pCommandBuffers[i], __LINE__, VALIDATION_ERROR_02057, "DS",
9762414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                        "vkCmdExecuteCommands(): Secondary Command Buffer (0x%p) executed within render pass (0x%" PRIxLEAST64
97634b6738a6adb4e813d66234defee5d18b7c84340dMike Weiblen                        ") must have had vkBeginCommandBuffer() called w/ VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT set. %s",
9764226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        pCommandBuffers[i], (uint64_t)pCB->activeRenderPass->renderPass,
97654b6738a6adb4e813d66234defee5d18b7c84340dMike Weiblen                        validation_error_map[VALIDATION_ERROR_02057]);
97665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                } else {
97675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    // Make sure render pass is compatible with parent command buffer pass if has continue
9768127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                    if (pCB->activeRenderPass->renderPass != secondary_rp_state->renderPass) {
9769fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes                        skip_call |=
9770fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes                            validateRenderPassCompatibility(dev_data, commandBuffer, pCB->activeRenderPass->createInfo.ptr(),
9771127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                                                            pCommandBuffers[i], secondary_rp_state->createInfo.ptr());
9772a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                    }
97731af6125615cd6dd9735d32e2ee8684abeff28d41Tobin Ehlis                    //  If framebuffer for secondary CB is not NULL, then it must match active FB from primaryCB
977483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |= validateFramebuffer(dev_data, commandBuffer, pCB, pCommandBuffers[i], pSubCB);
97755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
97765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                string errorString = "";
97771af6125615cd6dd9735d32e2ee8684abeff28d41Tobin Ehlis                // secondaryCB must have been created w/ RP compatible w/ primaryCB active renderpass
9778127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                if ((pCB->activeRenderPass->renderPass != secondary_rp_state->renderPass) &&
9779fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes                    !verify_renderpass_compatibility(dev_data, pCB->activeRenderPass->createInfo.ptr(),
9780127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                                                     secondary_rp_state->createInfo.ptr(), errorString)) {
978183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |= log_msg(
97825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
97835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        (uint64_t)pCommandBuffers[i], __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE, "DS",
9784414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                        "vkCmdExecuteCommands(): Secondary Command Buffer (0x%p) w/ render pass (0x%" PRIxLEAST64
9785414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                        ") is incompatible w/ primary command buffer (0x%p) w/ render pass (0x%" PRIxLEAST64 ") due to: %s",
9786226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        pCommandBuffers[i], (uint64_t)pSubCB->beginInfo.pInheritanceInfo->renderPass, commandBuffer,
9787ee691f5c5fa87aac3750454d2bca2cb582e4e817Chris Forbes                        (uint64_t)pCB->activeRenderPass->renderPass, errorString.c_str());
97885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
97895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
97905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // TODO(mlentine): Move more logic into this method
979183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= validateSecondaryCommandBufferState(dev_data, pCB, pSubCB);
979251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            skip_call |= validateCommandBufferState(dev_data, pSubCB, "vkCmdExecuteCommands()", 0);
97935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Secondary cmdBuffers are considered pending execution starting w/
97945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // being recorded
97955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
97965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (dev_data->globalInFlightCmdBuffers.find(pSubCB->commandBuffer) != dev_data->globalInFlightCmdBuffers.end()) {
9797cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
9798cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)(pCB->commandBuffer), __LINE__,
9799cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         VALIDATION_ERROR_00154, "DS",
9800cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         "Attempt to simultaneously execute command buffer 0x%p"
9801cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         " without VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set! %s",
9802cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         pCB->commandBuffer, validation_error_map[VALIDATION_ERROR_00154]);
98035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
98045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT) {
98055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    // Warn that non-simultaneous secondary cmd buffer renders primary non-simultaneous
980683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |= log_msg(
98075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
98085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        (uint64_t)(pCommandBuffers[i]), __LINE__, DRAWSTATE_INVALID_CB_SIMULTANEOUS_USE, "DS",
9809226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "vkCmdExecuteCommands(): Secondary Command Buffer (0x%p) "
9810226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set and will cause primary command buffer "
9811226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "(0x%p) to be treated as if it does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT "
981283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                        "set, even though it does.",
9813226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        pCommandBuffers[i], pCB->commandBuffer);
98145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    pCB->beginInfo.flags &= ~VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
98155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
98165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
9817f71dd305f197826a61f398bff725267a20ea1d90Chris Forbes            if (!pCB->activeQueries.empty() && !dev_data->enabled_features.inheritedQueries) {
9818cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                skip_call |=
9819cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9820cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            reinterpret_cast<uint64_t>(pCommandBuffers[i]), __LINE__, VALIDATION_ERROR_02062, "DS",
9821cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "vkCmdExecuteCommands(): Secondary Command Buffer "
9822cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "(0x%p) cannot be submitted with a query in "
9823cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "flight and inherited queries not "
9824cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "supported on this device. %s",
9825cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            pCommandBuffers[i], validation_error_map[VALIDATION_ERROR_02062]);
98265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
98278567fecbf563420f5900ade277ca68908aa87259Tobin Ehlis            // Propagate layout transitions to the primary cmd buffer
98288567fecbf563420f5900ade277ca68908aa87259Tobin Ehlis            for (auto ilm_entry : pSubCB->imageLayoutMap) {
982955867dbad6ae423b3bd78c15f6771031a710b5adMark Lobodzinski                SetLayout(dev_data, pCB, ilm_entry.first, ilm_entry.second);
98308567fecbf563420f5900ade277ca68908aa87259Tobin Ehlis            }
98315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pSubCB->primaryCommandBuffer = pCB->commandBuffer;
98325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pCB->secondaryCommandBuffers.insert(pSubCB->commandBuffer);
98335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->globalInFlightCmdBuffers.insert(pSubCB->commandBuffer);
9834d4ee9fdb2def1e9dc70c5627c9103e264471b8ebMichael Lentine            for (auto &function : pSubCB->queryUpdates) {
9835d4ee9fdb2def1e9dc70c5627c9103e264471b8ebMichael Lentine                pCB->queryUpdates.push_back(function);
9836d4ee9fdb2def1e9dc70c5627c9103e264471b8ebMichael Lentine            }
98375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
98389bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt        skip_call |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdExecuteComands", VALIDATION_ERROR_00163);
983929f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_EXECUTECOMMANDS, "vkCmdExecuteComands()");
98401ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_EXECUTECOMMANDS);
98415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9842b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
9843cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdExecuteCommands(commandBuffer, commandBuffersCount, pCommandBuffers);
98445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
98455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9846bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL MapMemory(VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size, VkFlags flags,
9847bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         void **ppData) {
984856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
98495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9850e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
98515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
9852b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
98539a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
9854cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    if (mem_info) {
9855f541bf53dee6daf82a4c8304354eac599a884d29Tobin Ehlis        // TODO : This could me more fine-grained to track just region that is valid
9856f541bf53dee6daf82a4c8304354eac599a884d29Tobin Ehlis        mem_info->global_valid = true;
9857623548a271287ae55415e45e3c654ee66d4e79ffTobin Ehlis        auto end_offset = (VK_WHOLE_SIZE == size) ? mem_info->alloc_info.allocationSize - 1 : offset + size - 1;
9858c3340a06ecac4d7b9540592cae339f8fc224d0b1Mark Lobodzinski        skip_call |= ValidateMapImageLayouts(dev_data, device, mem_info, offset, end_offset);
9859cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis        // TODO : Do we need to create new "bound_range" for the mapped range?
9860623548a271287ae55415e45e3c654ee66d4e79ffTobin Ehlis        SetMemRangesValid(dev_data, mem_info, offset, end_offset);
9861cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis        if ((dev_data->phys_dev_mem_props.memoryTypes[mem_info->alloc_info.memoryTypeIndex].propertyFlags &
9862b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis             VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) {
98632fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen            skip_call = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
98642fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                (uint64_t)mem, __LINE__, VALIDATION_ERROR_00629, "MEM",
98652fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                "Mapping Memory without VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT set: mem obj 0x%" PRIxLEAST64 ". %s",
98662fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                (uint64_t)mem, validation_error_map[VALIDATION_ERROR_00629]);
98675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
98685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9869f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis    skip_call |= ValidateMapMemRange(dev_data, mem, offset, size);
9870b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
98715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9872e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    if (!skip_call) {
98734a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.MapMemory(device, mem, offset, size, flags, ppData);
98747c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis        if (VK_SUCCESS == result) {
98757c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis            lock.lock();
9876cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis            // TODO : What's the point of this range? See comment on creating new "bound_range" above, which may replace this
98777c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis            storeMemRanges(dev_data, mem, offset, size);
98785f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            initializeAndTrackMemory(dev_data, mem, offset, size, ppData);
98797c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis            lock.unlock();
98807c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis        }
98815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
98825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
98835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
98845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
988589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL UnmapMemory(VkDevice device, VkDeviceMemory mem) {
988656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
988783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
98885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9889b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
98908860b85a52096f9f9b28616bc37feed505497a54Chris Forbes    skip_call |= deleteMemRanges(dev_data, mem);
9891b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
989283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (!skip_call) {
98934a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.UnmapMemory(device, mem);
98945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
98955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
98965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
98978860b85a52096f9f9b28616bc37feed505497a54Chris Forbesstatic bool validateMemoryIsMapped(layer_data *dev_data, const char *funcName, uint32_t memRangeCount,
9898e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                                   const VkMappedMemoryRange *pMemRanges) {
9899c7ee6f2fe100c1aacfaa0872832717c906bb8a4aMark Lobodzinski    bool skip = false;
99005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < memRangeCount; ++i) {
99019a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto mem_info = GetMemObjInfo(dev_data, pMemRanges[i].memory);
990257fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        if (mem_info) {
9903f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski            if (pMemRanges[i].size == VK_WHOLE_SIZE) {
9904f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                if (mem_info->mem_range.offset > pMemRanges[i].offset) {
9905cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
9906cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)pMemRanges[i].memory, __LINE__,
9907cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    VALIDATION_ERROR_00643, "MEM", "%s: Flush/Invalidate offset (" PRINTF_SIZE_T_SPECIFIER
9908cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                                   ") is less than Memory Object's offset "
9909cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                                   "(" PRINTF_SIZE_T_SPECIFIER "). %s",
9910cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    funcName, static_cast<size_t>(pMemRanges[i].offset),
9911cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    static_cast<size_t>(mem_info->mem_range.offset), validation_error_map[VALIDATION_ERROR_00643]);
9912f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                }
9913f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski            } else {
9914f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                const uint64_t data_end = (mem_info->mem_range.size == VK_WHOLE_SIZE)
9915f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                              ? mem_info->alloc_info.allocationSize
9916f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                              : (mem_info->mem_range.offset + mem_info->mem_range.size);
9917f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                if ((mem_info->mem_range.offset > pMemRanges[i].offset) ||
9918f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                    (data_end < (pMemRanges[i].offset + pMemRanges[i].size))) {
9919c7ee6f2fe100c1aacfaa0872832717c906bb8a4aMark Lobodzinski                    skip |=
9920f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
9921f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                (uint64_t)pMemRanges[i].memory, __LINE__, VALIDATION_ERROR_00642, "MEM",
9922f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                "%s: Flush/Invalidate size or offset (" PRINTF_SIZE_T_SPECIFIER ", " PRINTF_SIZE_T_SPECIFIER
9923f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                ") exceed the Memory Object's upper-bound "
9924f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                "(" PRINTF_SIZE_T_SPECIFIER "). %s",
9925f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                funcName, static_cast<size_t>(pMemRanges[i].offset + pMemRanges[i].size),
9926f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                static_cast<size_t>(pMemRanges[i].offset), static_cast<size_t>(data_end),
9927f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                validation_error_map[VALIDATION_ERROR_00642]);
9928f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                }
99295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
99305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
99315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9932c7ee6f2fe100c1aacfaa0872832717c906bb8a4aMark Lobodzinski    return skip;
99335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
99345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9935bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinskistatic bool ValidateAndCopyNoncoherentMemoryToDriver(layer_data *dev_data, uint32_t mem_range_count,
9936bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                                     const VkMappedMemoryRange *mem_ranges) {
9937bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski    bool skip = false;
9938bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski    for (uint32_t i = 0; i < mem_range_count; ++i) {
99399a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto mem_info = GetMemObjInfo(dev_data, mem_ranges[i].memory);
994057fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        if (mem_info) {
99415f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            if (mem_info->shadow_copy) {
99425f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                VkDeviceSize size = (mem_info->mem_range.size != VK_WHOLE_SIZE)
99435f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                        ? mem_info->mem_range.size
9944d8a53ade6b5501256798a8b4ec0bc14f72adc1faTobin Ehlis                                        : (mem_info->alloc_info.allocationSize - mem_info->mem_range.offset);
99455f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                char *data = static_cast<char *>(mem_info->shadow_copy);
99465f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                for (uint64_t j = 0; j < mem_info->shadow_pad_size; ++j) {
99475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    if (data[j] != NoncoherentMemoryFillValue) {
9948bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
9949bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                        VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)mem_ranges[i].memory, __LINE__,
9950bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                        MEMTRACK_INVALID_MAP, "MEM", "Memory underflow was detected on mem obj 0x%" PRIxLEAST64,
9951bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                        (uint64_t)mem_ranges[i].memory);
99525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
99535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
99545f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                for (uint64_t j = (size + mem_info->shadow_pad_size); j < (2 * mem_info->shadow_pad_size + size); ++j) {
99555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    if (data[j] != NoncoherentMemoryFillValue) {
9956bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
9957bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                        VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)mem_ranges[i].memory, __LINE__,
9958bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                        MEMTRACK_INVALID_MAP, "MEM", "Memory overflow was detected on mem obj 0x%" PRIxLEAST64,
9959bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                        (uint64_t)mem_ranges[i].memory);
99605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
99615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
99625f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                memcpy(mem_info->p_driver_data, static_cast<void *>(data + mem_info->shadow_pad_size), (size_t)(size));
99635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
99645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
99655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9966bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski    return skip;
99675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
99685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9969bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinskistatic void CopyNoncoherentMemoryFromDriver(layer_data *dev_data, uint32_t mem_range_count, const VkMappedMemoryRange *mem_ranges) {
9970bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski    for (uint32_t i = 0; i < mem_range_count; ++i) {
99719a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto mem_info = GetMemObjInfo(dev_data, mem_ranges[i].memory);
99725f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski        if (mem_info && mem_info->shadow_copy) {
99735f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            VkDeviceSize size = (mem_info->mem_range.size != VK_WHOLE_SIZE)
99745f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                    ? mem_info->mem_range.size
99755f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                    : (mem_info->alloc_info.allocationSize - mem_ranges[i].offset);
99765f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            char *data = static_cast<char *>(mem_info->shadow_copy);
99775f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            memcpy(data + mem_info->shadow_pad_size, mem_info->p_driver_data, (size_t)(size));
99789e21e56fc23ade48efd3752d2e2729895eb90349Mark Lobodzinski        }
99799e21e56fc23ade48efd3752d2e2729895eb90349Mark Lobodzinski    }
99809e21e56fc23ade48efd3752d2e2729895eb90349Mark Lobodzinski}
99819e21e56fc23ade48efd3752d2e2729895eb90349Mark Lobodzinski
9982ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinskistatic bool ValidateMappedMemoryRangeDeviceLimits(layer_data *dev_data, const char *func_name, uint32_t mem_range_count,
9983ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                                                  const VkMappedMemoryRange *mem_ranges) {
9984ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski    bool skip = false;
9985ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski    for (uint32_t i = 0; i < mem_range_count; ++i) {
9986ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski        uint64_t atom_size = dev_data->phys_dev_properties.properties.limits.nonCoherentAtomSize;
9987ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski        if (vk_safe_modulo(mem_ranges[i].offset, atom_size) != 0) {
9988ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
9989ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            __LINE__, VALIDATION_ERROR_00644, "MEM",
9990ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            "%s: Offset in pMemRanges[%d] is 0x%" PRIxLEAST64
9991ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            ", which is not a multiple of VkPhysicalDeviceLimits::nonCoherentAtomSize (0x%" PRIxLEAST64 "). %s",
9992ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            func_name, i, mem_ranges[i].offset, atom_size, validation_error_map[VALIDATION_ERROR_00644]);
9993ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski        }
9994ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski        if ((mem_ranges[i].size != VK_WHOLE_SIZE) && (vk_safe_modulo(mem_ranges[i].size, atom_size) != 0)) {
9995ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
9996ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            __LINE__, VALIDATION_ERROR_00645, "MEM",
9997ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            "%s: Size in pMemRanges[%d] is 0x%" PRIxLEAST64
9998ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            ", which is not a multiple of VkPhysicalDeviceLimits::nonCoherentAtomSize (0x%" PRIxLEAST64 "). %s",
9999ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            func_name, i, mem_ranges[i].size, atom_size, validation_error_map[VALIDATION_ERROR_00645]);
10000ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski        }
10001ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski    }
10002ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski    return skip;
10003ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski}
10004ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski
1000580e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinskistatic bool PreCallValidateFlushMappedMemoryRanges(layer_data *dev_data, uint32_t mem_range_count,
1000680e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski                                                   const VkMappedMemoryRange *mem_ranges) {
1000780e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    bool skip = false;
1000880e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    std::lock_guard<std::mutex> lock(global_lock);
1000980e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    skip |= ValidateAndCopyNoncoherentMemoryToDriver(dev_data, mem_range_count, mem_ranges);
1001080e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    skip |= validateMemoryIsMapped(dev_data, "vkFlushMappedMemoryRanges", mem_range_count, mem_ranges);
1001180e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    return skip;
1001280e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski}
1001380e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski
10014bba0de708d942e9a2187158915856995db1c5a4dMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL FlushMappedMemoryRanges(VkDevice device, uint32_t memRangeCount,
10015bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                                       const VkMappedMemoryRange *pMemRanges) {
100165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
1001756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
100185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1001980e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    if (!PreCallValidateFlushMappedMemoryRanges(dev_data, memRangeCount, pMemRanges)) {
100204a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.FlushMappedMemoryRanges(device, memRangeCount, pMemRanges);
100215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
100225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
100235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
100245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1002580e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinskistatic bool PreCallValidateInvalidateMappedMemoryRanges(layer_data *dev_data, uint32_t mem_range_count,
1002680e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski                                                        const VkMappedMemoryRange *mem_ranges) {
1002780e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    bool skip = false;
1002880e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    std::lock_guard<std::mutex> lock(global_lock);
1002980e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    skip |= validateMemoryIsMapped(dev_data, "vkInvalidateMappedMemoryRanges", mem_range_count, mem_ranges);
1003080e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    return skip;
1003180e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski}
1003280e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski
1003380e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinskistatic void PostCallRecordInvalidateMappedMemoryRanges(layer_data *dev_data, uint32_t mem_range_count,
1003480e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski                                                       const VkMappedMemoryRange *mem_ranges) {
1003580e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    std::lock_guard<std::mutex> lock(global_lock);
1003680e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    // Update our shadow copy with modified driver data
1003780e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    CopyNoncoherentMemoryFromDriver(dev_data, mem_range_count, mem_ranges);
1003880e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski}
1003980e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski
10040bba0de708d942e9a2187158915856995db1c5a4dMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL InvalidateMappedMemoryRanges(VkDevice device, uint32_t memRangeCount,
10041bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                                            const VkMappedMemoryRange *pMemRanges) {
100425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
1004356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
100445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1004580e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    if (!PreCallValidateInvalidateMappedMemoryRanges(dev_data, memRangeCount, pMemRanges)) {
100464a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.InvalidateMappedMemoryRanges(device, memRangeCount, pMemRanges);
1004780e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski        if (result == VK_SUCCESS) {
1004880e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski            PostCallRecordInvalidateMappedMemoryRanges(dev_data, memRangeCount, pMemRanges);
1004980e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski        }
100505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
100515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
100525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
100535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10054341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Strattonstatic bool PreCallValidateBindImageMemory(layer_data *dev_data, VkImage image, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
100550109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski    bool skip = false;
10056b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
10057341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton
100589a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto image_state = GetImageState(dev_data, image);
100591facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (image_state) {
1006094c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis        // Track objects tied to memory
1006147aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski        uint64_t image_handle = reinterpret_cast<uint64_t &>(image);
10062c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        skip = ValidateSetMemBinding(dev_data, mem, image_handle, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, "vkBindImageMemory()");
10063ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis        if (!image_state->memory_requirements_checked) {
10064ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            // There's not an explicit requirement in the spec to call vkGetImageMemoryRequirements() prior to calling
10065341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton            // BindImageMemory but it's implied in that memory being bound must conform with VkMemoryRequirements from
10066341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton            // vkGetImageMemoryRequirements()
100670109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
100680109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski                            image_handle, __LINE__, DRAWSTATE_INVALID_IMAGE, "DS",
100690109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski                            "vkBindImageMemory(): Binding memory to image 0x%" PRIxLEAST64
100700109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski                            " but vkGetImageMemoryRequirements() has not been called on that image.",
100710109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski                            image_handle);
10072ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            // Make the call for them so we can verify the state
10073ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            lock.unlock();
10074341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton            dev_data->dispatch_table.GetImageMemoryRequirements(dev_data->device, image, &image_state->requirements);
10075ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            lock.lock();
10076ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis        }
1007747aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
1007847aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski        // Track and validate bound memory range information
100799a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto mem_info = GetMemObjInfo(dev_data, mem);
1008057fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        if (mem_info) {
100810109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski            skip |= InsertImageMemoryRange(dev_data, image, mem_info, memoryOffset, image_state->requirements,
1008274300755ed9ec780d6073af71e47f201217008d6Cort Stratton                                           image_state->createInfo.tiling == VK_IMAGE_TILING_LINEAR, "vkBindImageMemory()");
1008374300755ed9ec780d6073af71e47f201217008d6Cort Stratton            skip |= ValidateMemoryTypes(dev_data, mem_info, image_state->requirements.memoryTypeBits, "vkBindImageMemory()",
100840109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski                                        VALIDATION_ERROR_00806);
1008547aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski        }
10086341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    }
10087341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    return skip;
10088341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton}
1008947aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
10090341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Strattonstatic void PostCallRecordBindImageMemory(layer_data *dev_data, VkImage image, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
10091341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    std::unique_lock<std::mutex> lock(global_lock);
10092341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    auto image_state = GetImageState(dev_data, image);
10093341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    if (image_state) {
10094c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        // Track objects tied to memory
10095c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        uint64_t image_handle = reinterpret_cast<uint64_t &>(image);
10096c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        SetMemBinding(dev_data, mem, image_handle, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, "vkBindImageMemory()");
10097c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton
10098341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton        image_state->binding.mem = mem;
10099341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton        image_state->binding.offset = memoryOffset;
10100341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton        image_state->binding.size = image_state->requirements.size;
10101341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    }
10102341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton}
10103341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton
10104341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort StrattonVKAPI_ATTR VkResult VKAPI_CALL BindImageMemory(VkDevice device, VkImage image, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
10105341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
10106341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
10107341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    bool skip = PreCallValidateBindImageMemory(dev_data, image, mem, memoryOffset);
10108341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    if (!skip) {
10109341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton        result = dev_data->dispatch_table.BindImageMemory(device, image, mem, memoryOffset);
10110341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton        if (result == VK_SUCCESS) {
10111341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton            PostCallRecordBindImageMemory(dev_data, image, mem, memoryOffset);
1011294c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis        }
101135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
101145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
101155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
101165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1011789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL SetEvent(VkDevice device, VkEvent event) {
101183ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis    bool skip_call = false;
101193ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
1012056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
10121b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
101229a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto event_state = GetEventNode(dev_data, event);
101234710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis    if (event_state) {
101244710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        event_state->needsSignaled = false;
101254710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        event_state->stageMask = VK_PIPELINE_STAGE_HOST_BIT;
101264710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        if (event_state->write_in_use) {
101273ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT,
101283ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis                                 reinterpret_cast<const uint64_t &>(event), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
10129414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                                 "Cannot call vkSetEvent() on event 0x%" PRIxLEAST64 " that is already in use by a command buffer.",
101303ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis                                 reinterpret_cast<const uint64_t &>(event));
101313ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis        }
101323ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis    }
10133b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
101346fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    // Host setting event is visible to all queues immediately so update stageMask for any queue that's seen this event
101356fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    // TODO : For correctness this needs separate fix to verify that app doesn't make incorrect assumptions about the
101366fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    // ordering of this command in relation to vkCmd[Set|Reset]Events (see GH297)
101376fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    for (auto queue_data : dev_data->queueMap) {
101386fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis        auto event_entry = queue_data.second.eventToStageMap.find(event);
101396fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis        if (event_entry != queue_data.second.eventToStageMap.end()) {
101406fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis            event_entry->second |= VK_PIPELINE_STAGE_HOST_BIT;
101416fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis        }
101426fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    }
10143cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) result = dev_data->dispatch_table.SetEvent(device, event);
101445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
101455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
101465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10147bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL QueueBindSparse(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo *pBindInfo,
10148bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                               VkFence fence) {
1014956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
101505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
10151e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
10152b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
101539a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pFence = GetFenceNode(dev_data, fence);
101549a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pQueue = GetQueueState(dev_data, queue);
10155651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
101564b38d3aa8b6be6a7f5bebb472ab439da0562824fTobin Ehlis    // First verify that fence is not in use
10157651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    skip_call |= ValidateFenceForSubmit(dev_data, pFence);
10158651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
101599867daedbf52debc77d6568162ee21e071699b80Chris Forbes    if (pFence) {
101609867daedbf52debc77d6568162ee21e071699b80Chris Forbes        SubmitFence(pQueue, pFence, bindInfoCount);
101614b38d3aa8b6be6a7f5bebb472ab439da0562824fTobin Ehlis    }
10162651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
101631344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis    for (uint32_t bindIdx = 0; bindIdx < bindInfoCount; ++bindIdx) {
101641344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        const VkBindSparseInfo &bindInfo = pBindInfo[bindIdx];
101655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Track objects tied to memory
101661344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t j = 0; j < bindInfo.bufferBindCount; j++) {
101671344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis            for (uint32_t k = 0; k < bindInfo.pBufferBinds[j].bindCount; k++) {
10168f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                auto sparse_binding = bindInfo.pBufferBinds[j].pBinds[k];
10169f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                if (SetSparseMemBinding(dev_data, {sparse_binding.memory, sparse_binding.memoryOffset, sparse_binding.size},
10170f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                                        (uint64_t)bindInfo.pBufferBinds[j].buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
10171f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                                        "vkQueueBindSparse"))
10172e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                    skip_call = true;
101735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
101745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
101751344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t j = 0; j < bindInfo.imageOpaqueBindCount; j++) {
101761344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis            for (uint32_t k = 0; k < bindInfo.pImageOpaqueBinds[j].bindCount; k++) {
10177f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                auto sparse_binding = bindInfo.pImageOpaqueBinds[j].pBinds[k];
10178f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                if (SetSparseMemBinding(dev_data, {sparse_binding.memory, sparse_binding.memoryOffset, sparse_binding.size},
10179f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                                        (uint64_t)bindInfo.pImageOpaqueBinds[j].image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
10180f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                                        "vkQueueBindSparse"))
10181e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                    skip_call = true;
101825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
101835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
101841344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t j = 0; j < bindInfo.imageBindCount; j++) {
101851344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis            for (uint32_t k = 0; k < bindInfo.pImageBinds[j].bindCount; k++) {
10186f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                auto sparse_binding = bindInfo.pImageBinds[j].pBinds[k];
10187f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                // TODO: This size is broken for non-opaque bindings, need to update to comprehend full sparse binding data
10188f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                VkDeviceSize size = sparse_binding.extent.depth * sparse_binding.extent.height * sparse_binding.extent.width * 4;
10189f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                if (SetSparseMemBinding(dev_data, {sparse_binding.memory, sparse_binding.memoryOffset, size},
10190f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                                        (uint64_t)bindInfo.pImageBinds[j].image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
10191f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                                        "vkQueueBindSparse"))
10192e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                    skip_call = true;
101935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
101945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
101959867daedbf52debc77d6568162ee21e071699b80Chris Forbes
101969867daedbf52debc77d6568162ee21e071699b80Chris Forbes        std::vector<SEMAPHORE_WAIT> semaphore_waits;
101979867daedbf52debc77d6568162ee21e071699b80Chris Forbes        std::vector<VkSemaphore> semaphore_signals;
101981344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t i = 0; i < bindInfo.waitSemaphoreCount; ++i) {
1019901a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            VkSemaphore semaphore = bindInfo.pWaitSemaphores[i];
102009a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
1020101a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            if (pSemaphore) {
1020201a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes                if (pSemaphore->signaled) {
102039867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    if (pSemaphore->signaler.first != VK_NULL_HANDLE) {
102049867daedbf52debc77d6568162ee21e071699b80Chris Forbes                        semaphore_waits.push_back({semaphore, pSemaphore->signaler.first, pSemaphore->signaler.second});
102059867daedbf52debc77d6568162ee21e071699b80Chris Forbes                        pSemaphore->in_use.fetch_add(1);
102069867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    }
102079867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->signaler.first = VK_NULL_HANDLE;
1020801a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes                    pSemaphore->signaled = false;
102091344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                } else {
10210226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    skip_call |= log_msg(
10211226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
10212226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        reinterpret_cast<const uint64_t &>(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
10213226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "vkQueueBindSparse: Queue 0x%p is waiting on semaphore 0x%" PRIx64 " that has no way to be signaled.",
10214226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        queue, reinterpret_cast<const uint64_t &>(semaphore));
102155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
102165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
102175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
102181344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t i = 0; i < bindInfo.signalSemaphoreCount; ++i) {
1021901a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            VkSemaphore semaphore = bindInfo.pSignalSemaphores[i];
102209a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
1022101a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            if (pSemaphore) {
1022201a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes                if (pSemaphore->signaled) {
102235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    skip_call =
102245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
102251344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                                reinterpret_cast<const uint64_t &>(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
10226226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                "vkQueueBindSparse: Queue 0x%p is signaling semaphore 0x%" PRIx64
102271344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                                ", but that semaphore is already signaled.",
10228226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                queue, reinterpret_cast<const uint64_t &>(semaphore));
10229bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                } else {
102309867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->signaler.first = queue;
102319867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->signaler.second = pQueue->seq + pQueue->submissions.size() + 1;
102329867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->signaled = true;
102339867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->in_use.fetch_add(1);
102349867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    semaphore_signals.push_back(semaphore);
102359867daedbf52debc77d6568162ee21e071699b80Chris Forbes                }
102365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
102375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
102389867daedbf52debc77d6568162ee21e071699b80Chris Forbes
10239bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pQueue->submissions.emplace_back(std::vector<VkCommandBuffer>(), semaphore_waits, semaphore_signals,
102409867daedbf52debc77d6568162ee21e071699b80Chris Forbes                                         bindIdx == bindInfoCount - 1 ? fence : VK_NULL_HANDLE);
102415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
102429867daedbf52debc77d6568162ee21e071699b80Chris Forbes
102439867daedbf52debc77d6568162ee21e071699b80Chris Forbes    if (pFence && !bindInfoCount) {
102449867daedbf52debc77d6568162ee21e071699b80Chris Forbes        // No work to do, just dropping a fence in the queue by itself.
10245bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pQueue->submissions.emplace_back(std::vector<VkCommandBuffer>(), std::vector<SEMAPHORE_WAIT>(), std::vector<VkSemaphore>(),
102469867daedbf52debc77d6568162ee21e071699b80Chris Forbes                                         fence);
102479867daedbf52debc77d6568162ee21e071699b80Chris Forbes    }
102489867daedbf52debc77d6568162ee21e071699b80Chris Forbes
10249b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
102505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10251cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) return dev_data->dispatch_table.QueueBindSparse(queue, bindInfoCount, pBindInfo, fence);
102525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
102535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
102545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
102555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1025689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateSemaphore(VkDevice device, const VkSemaphoreCreateInfo *pCreateInfo,
1025789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                               const VkAllocationCallbacks *pAllocator, VkSemaphore *pSemaphore) {
1025856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
102594a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateSemaphore(device, pCreateInfo, pAllocator, pSemaphore);
102605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
10261b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
10262bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        SEMAPHORE_NODE *sNode = &dev_data->semaphoreMap[*pSemaphore];
102639867daedbf52debc77d6568162ee21e071699b80Chris Forbes        sNode->signaler.first = VK_NULL_HANDLE;
102649867daedbf52debc77d6568162ee21e071699b80Chris Forbes        sNode->signaler.second = 0;
102651344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        sNode->signaled = false;
102665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
102675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
102685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
102695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10270bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateEvent(VkDevice device, const VkEventCreateInfo *pCreateInfo,
10271bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           const VkAllocationCallbacks *pAllocator, VkEvent *pEvent) {
1027256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
102734a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateEvent(device, pCreateInfo, pAllocator, pEvent);
102745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
10275b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
102765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->eventMap[*pEvent].needsSignaled = false;
10277293ecfc5e69ed3978a8c04518166d828294870a4Tony Barbour        dev_data->eventMap[*pEvent].write_in_use = 0;
102785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->eventMap[*pEvent].stageMask = VkPipelineStageFlags(0);
102795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
102805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
102815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
102825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
102839ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinskistatic bool PreCallValidateCreateSwapchainKHR(layer_data *dev_data, const char *func_name,
102849ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                                              VkSwapchainCreateInfoKHR const *pCreateInfo, SURFACE_STATE *surface_state,
102859ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                                              SWAPCHAIN_NODE *old_swapchain_state) {
10286d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    auto most_recent_swapchain = surface_state->swapchain ? surface_state->swapchain : surface_state->old_swapchain;
10287d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes
102884bd5f453535de3d3423ff1f9995b4acb15f791d2Chris Forbes    // TODO: revisit this. some of these rules are being relaxed.
10289d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    if (most_recent_swapchain != old_swapchain_state || (surface_state->old_swapchain && surface_state->swapchain)) {
10290d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
10291d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes                    reinterpret_cast<uint64_t>(dev_data->device), __LINE__, DRAWSTATE_SWAPCHAIN_ALREADY_EXISTS, "DS",
102929ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    "%s: surface has an existing swapchain other than oldSwapchain", func_name))
10293d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes            return true;
10294d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    }
10295d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    if (old_swapchain_state && old_swapchain_state->createInfo.surface != pCreateInfo->surface) {
10296d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
10297d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes                    reinterpret_cast<uint64_t const &>(pCreateInfo->oldSwapchain), __LINE__, DRAWSTATE_SWAPCHAIN_WRONG_SURFACE,
102989ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    "DS", "%s: pCreateInfo->oldSwapchain's surface is not pCreateInfo->surface", func_name))
10299d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes            return true;
10300d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    }
103019a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(dev_data->instance_data, dev_data->physical_device);
103027de258f87ca1192db116a66b209253793d276ebcChris Forbes    if (physical_device_state->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState == UNCALLED) {
103037de258f87ca1192db116a66b209253793d276ebcChris Forbes        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
103047de258f87ca1192db116a66b209253793d276ebcChris Forbes                    reinterpret_cast<uint64_t>(dev_data->physical_device), __LINE__, DRAWSTATE_SWAPCHAIN_CREATE_BEFORE_QUERY, "DS",
103059ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    "%s: surface capabilities not retrieved for this physical device", func_name))
103067de258f87ca1192db116a66b209253793d276ebcChris Forbes            return true;
10307cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    } else {  // have valid capabilities
103085c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        auto &capabilities = physical_device_state->surfaceCapabilities;
103099ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->minImageCount against VkSurfaceCapabilitiesKHR::{min|max}ImageCount:
103102fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen        if (pCreateInfo->minImageCount < capabilities.minImageCount) {
103112fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
103122fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02331, "DS",
103139ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with minImageCount = %d, which is outside the bounds returned "
103142fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        "by vkGetPhysicalDeviceSurfaceCapabilitiesKHR() (i.e. minImageCount = %d, maxImageCount = %d). %s",
103159ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->minImageCount, capabilities.minImageCount, capabilities.maxImageCount,
103162fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        validation_error_map[VALIDATION_ERROR_02331]))
103172fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                return true;
103182fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen        }
103192fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen
103202fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen        if ((capabilities.maxImageCount > 0) && (pCreateInfo->minImageCount > capabilities.maxImageCount)) {
103215c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
103222fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02332, "DS",
103239ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with minImageCount = %d, which is outside the bounds returned "
103242fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        "by vkGetPhysicalDeviceSurfaceCapabilitiesKHR() (i.e. minImageCount = %d, maxImageCount = %d). %s",
103259ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->minImageCount, capabilities.minImageCount, capabilities.maxImageCount,
103262fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        validation_error_map[VALIDATION_ERROR_02332]))
103275c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
103285c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
103292fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen
103309ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->imageExtent against VkSurfaceCapabilitiesKHR::{current|min|max}ImageExtent:
103312e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill        if ((capabilities.currentExtent.width == kSurfaceSizeFromSwapchain) &&
103322e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill            ((pCreateInfo->imageExtent.width < capabilities.minImageExtent.width) ||
103332e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill             (pCreateInfo->imageExtent.width > capabilities.maxImageExtent.width) ||
103342e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill             (pCreateInfo->imageExtent.height < capabilities.minImageExtent.height) ||
103352e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill             (pCreateInfo->imageExtent.height > capabilities.maxImageExtent.height))) {
103365c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
103372fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02334, "DS",
103389ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with imageExtent = (%d,%d), which is outside the bounds returned by "
103399ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "vkGetPhysicalDeviceSurfaceCapabilitiesKHR(): currentExtent = (%d,%d), minImageExtent = (%d,%d), "
103409ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "maxImageExtent = (%d,%d). %s",
103419ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->imageExtent.width, pCreateInfo->imageExtent.height,
103429ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        capabilities.currentExtent.width, capabilities.currentExtent.height, capabilities.minImageExtent.width,
103439ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        capabilities.minImageExtent.height, capabilities.maxImageExtent.width, capabilities.maxImageExtent.height,
103442fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        validation_error_map[VALIDATION_ERROR_02334]))
103455c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
103465c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
103472e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill        if ((capabilities.currentExtent.width != kSurfaceSizeFromSwapchain) &&
103482e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill            ((pCreateInfo->imageExtent.width != capabilities.currentExtent.width) ||
103492e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill             (pCreateInfo->imageExtent.height != capabilities.currentExtent.height))) {
103505c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
103512fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02334, "DS",
103529ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with imageExtent = (%d,%d), which is not equal to the currentExtent = (%d,%d) returned by "
103539ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "vkGetPhysicalDeviceSurfaceCapabilitiesKHR(). %s",
103549ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->imageExtent.width, pCreateInfo->imageExtent.height,
103559ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        capabilities.currentExtent.width, capabilities.currentExtent.height,
103562fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        validation_error_map[VALIDATION_ERROR_02334]))
103575c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
103585c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
103599ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // pCreateInfo->preTransform should have exactly one bit set, and that bit must also be set in
103609ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // VkSurfaceCapabilitiesKHR::supportedTransforms.
103615c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        if (!pCreateInfo->preTransform || (pCreateInfo->preTransform & (pCreateInfo->preTransform - 1)) ||
103625c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            !(pCreateInfo->preTransform & capabilities.supportedTransforms)) {
103639ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            // This is an error situation; one for which we'd like to give the developer a helpful, multi-line error message.  Build
103649ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            // it up a little at a time, and then log it:
103655c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            std::string errorString = "";
103665c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            char str[1024];
103675c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            // Here's the first part of the message:
103689ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            sprintf(str, "%s called with a non-supported pCreateInfo->preTransform (i.e. %s).  Supported values are:\n", func_name,
103695c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    string_VkSurfaceTransformFlagBitsKHR(pCreateInfo->preTransform));
103705c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            errorString += str;
103715c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            for (int i = 0; i < 32; i++) {
103725c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                // Build up the rest of the message:
103735c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                if ((1 << i) & capabilities.supportedTransforms) {
103745c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    const char *newStr = string_VkSurfaceTransformFlagBitsKHR((VkSurfaceTransformFlagBitsKHR)(1 << i));
103755c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    sprintf(str, "    %s\n", newStr);
103765c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    errorString += str;
103775c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                }
103785c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            }
103795c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            // Log the message that we've built up:
103805c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
103812fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t &>(dev_data->device), __LINE__, VALIDATION_ERROR_02339, "DS", "%s. %s",
103822fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        errorString.c_str(), validation_error_map[VALIDATION_ERROR_02339]))
103835c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
103845c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
103857b0d28d116977b91892f354e002edd760bdb86cbChris Forbes
103869ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // pCreateInfo->compositeAlpha should have exactly one bit set, and that bit must also be set in
103879ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // VkSurfaceCapabilitiesKHR::supportedCompositeAlpha
103885c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        if (!pCreateInfo->compositeAlpha || (pCreateInfo->compositeAlpha & (pCreateInfo->compositeAlpha - 1)) ||
103895c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            !((pCreateInfo->compositeAlpha) & capabilities.supportedCompositeAlpha)) {
103909ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            // This is an error situation; one for which we'd like to give the developer a helpful, multi-line error message.  Build
103919ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            // it up a little at a time, and then log it:
103925c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            std::string errorString = "";
103935c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            char str[1024];
103945c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            // Here's the first part of the message:
103959ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            sprintf(str, "%s called with a non-supported pCreateInfo->compositeAlpha (i.e. %s).  Supported values are:\n",
103969ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    func_name, string_VkCompositeAlphaFlagBitsKHR(pCreateInfo->compositeAlpha));
103975c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            errorString += str;
103985c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            for (int i = 0; i < 32; i++) {
103995c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                // Build up the rest of the message:
104005c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                if ((1 << i) & capabilities.supportedCompositeAlpha) {
104015c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    const char *newStr = string_VkCompositeAlphaFlagBitsKHR((VkCompositeAlphaFlagBitsKHR)(1 << i));
104025c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    sprintf(str, "    %s\n", newStr);
104035c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    errorString += str;
104045c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                }
104055c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            }
104065c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            // Log the message that we've built up:
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_02340, "DS", "%s. %s",
104092fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        errorString.c_str(), validation_error_map[VALIDATION_ERROR_02340]))
104105c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
104115c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
104129ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->imageArrayLayers against VkSurfaceCapabilitiesKHR::maxImageArrayLayers:
104135c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        if ((pCreateInfo->imageArrayLayers < 1) || (pCreateInfo->imageArrayLayers > capabilities.maxImageArrayLayers)) {
104145c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
104152fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02335, "DS",
104169ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with a non-supported imageArrayLayers (i.e. %d).  Minimum value is 1, maximum value is %d. %s",
104179ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->imageArrayLayers, capabilities.maxImageArrayLayers,
104182fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        validation_error_map[VALIDATION_ERROR_02335]))
104195c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
104205c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
104219ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->imageUsage against VkSurfaceCapabilitiesKHR::supportedUsageFlags:
104225c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        if (pCreateInfo->imageUsage != (pCreateInfo->imageUsage & capabilities.supportedUsageFlags)) {
104235c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
104242fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02336, "DS",
104259ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with a non-supported pCreateInfo->imageUsage (i.e. 0x%08x).  Supported flag bits are 0x%08x. %s",
104269ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->imageUsage, capabilities.supportedUsageFlags,
104279ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        validation_error_map[VALIDATION_ERROR_02336]))
104285c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
104295c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
104307de258f87ca1192db116a66b209253793d276ebcChris Forbes    }
10431d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes
104329ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski    // Validate pCreateInfo values with the results of vkGetPhysicalDeviceSurfaceFormatsKHR():
104335faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    if (physical_device_state->vkGetPhysicalDeviceSurfaceFormatsKHRState != QUERY_DETAILS) {
104345faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
104355faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    reinterpret_cast<uint64_t>(dev_data->device), __LINE__, DRAWSTATE_SWAPCHAIN_CREATE_BEFORE_QUERY, "DS",
104369ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    "%s called before calling vkGetPhysicalDeviceSurfaceFormatsKHR().", func_name))
104375faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            return true;
104385faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    } else {
104399ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->imageFormat against VkSurfaceFormatKHR::format:
104405faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        bool foundFormat = false;
104415faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        bool foundColorSpace = false;
104425faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        bool foundMatch = false;
104435faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        for (auto const &format : physical_device_state->surface_formats) {
104445faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            if (pCreateInfo->imageFormat == format.format) {
104459ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                // Validate pCreateInfo->imageColorSpace against VkSurfaceFormatKHR::colorSpace:
104465faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                foundFormat = true;
104475faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                if (pCreateInfo->imageColorSpace == format.colorSpace) {
104485faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    foundMatch = true;
104495faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    break;
104505faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                }
104515faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            } else {
104525faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                if (pCreateInfo->imageColorSpace == format.colorSpace) {
104535faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    foundColorSpace = true;
104545faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                }
104555faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            }
104565faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        }
104575faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        if (!foundMatch) {
104585faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            if (!foundFormat) {
104595faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
104602fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                            reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02333, "DS",
10461bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "%s called with a non-supported pCreateInfo->imageFormat (i.e. %d). %s", func_name,
10462bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            pCreateInfo->imageFormat, validation_error_map[VALIDATION_ERROR_02333]))
104632fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                    return true;
104642fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen            }
104652fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen            if (!foundColorSpace) {
104662fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
104672fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                            reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02333, "DS",
10468bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "%s called with a non-supported pCreateInfo->imageColorSpace (i.e. %d). %s", func_name,
10469bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            pCreateInfo->imageColorSpace, validation_error_map[VALIDATION_ERROR_02333]))
104705faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    return true;
104715faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            }
104725faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        }
104735faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    }
104745faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
104759ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski    // Validate pCreateInfo values with the results of vkGetPhysicalDeviceSurfacePresentModesKHR():
104769e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    if (physical_device_state->vkGetPhysicalDeviceSurfacePresentModesKHRState != QUERY_DETAILS) {
1047725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // FIFO is required to always be supported
104789e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        if (pCreateInfo->presentMode != VK_PRESENT_MODE_FIFO_KHR) {
104799e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
104809ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, DRAWSTATE_SWAPCHAIN_CREATE_BEFORE_QUERY, "DS",
104819ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called before calling vkGetPhysicalDeviceSurfacePresentModesKHR().", func_name))
104829e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                return true;
104839e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
104849e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    } else {
104859ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->presentMode against vkGetPhysicalDeviceSurfacePresentModesKHR():
10486bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        bool foundMatch = std::find(physical_device_state->present_modes.begin(), physical_device_state->present_modes.end(),
104879e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                                    pCreateInfo->presentMode) != physical_device_state->present_modes.end();
104889e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        if (!foundMatch) {
104899e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
104902fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02341, "DS",
104919ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with a non-supported presentMode (i.e. %s). %s", func_name,
104922fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        string_VkPresentModeKHR(pCreateInfo->presentMode), validation_error_map[VALIDATION_ERROR_02341]))
104939e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                return true;
104949e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
104959e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    }
104969e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
10497d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    return false;
10498d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes}
10499d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes
10500261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinskistatic void PostCallRecordCreateSwapchainKHR(layer_data *dev_data, VkResult result, const VkSwapchainCreateInfoKHR *pCreateInfo,
10501261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski                                             VkSwapchainKHR *pSwapchain, SURFACE_STATE *surface_state,
10502261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski                                             SWAPCHAIN_NODE *old_swapchain_state) {
105035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
10504b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
10505ddc5201048319558ce66701163a4546ee957af19Chris Forbes        auto swapchain_state = unique_ptr<SWAPCHAIN_NODE>(new SWAPCHAIN_NODE(pCreateInfo, *pSwapchain));
10506ddc5201048319558ce66701163a4546ee957af19Chris Forbes        surface_state->swapchain = swapchain_state.get();
10507ddc5201048319558ce66701163a4546ee957af19Chris Forbes        dev_data->device_extensions.swapchainMap[*pSwapchain] = std::move(swapchain_state);
10508ddc5201048319558ce66701163a4546ee957af19Chris Forbes    } else {
10509ddc5201048319558ce66701163a4546ee957af19Chris Forbes        surface_state->swapchain = nullptr;
105105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10511ddc5201048319558ce66701163a4546ee957af19Chris Forbes    // Spec requires that even if CreateSwapchainKHR fails, oldSwapchain behaves as replaced.
105125b5488456e5afa0487f95b805a2aba59b13d69f4Chris Forbes    if (old_swapchain_state) {
105135b5488456e5afa0487f95b805a2aba59b13d69f4Chris Forbes        old_swapchain_state->replaced = true;
105145b5488456e5afa0487f95b805a2aba59b13d69f4Chris Forbes    }
10515ddc5201048319558ce66701163a4546ee957af19Chris Forbes    surface_state->old_swapchain = old_swapchain_state;
10516261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski    return;
10517261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski}
10518261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski
10519261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo,
10520261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski                                                  const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchain) {
1052156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
105229a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto surface_state = GetSurfaceState(dev_data->instance_data, pCreateInfo->surface);
105239a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto old_swapchain_state = GetSwapchainNode(dev_data, pCreateInfo->oldSwapchain);
10524261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski
105259ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski    if (PreCallValidateCreateSwapchainKHR(dev_data, "vkCreateSwapChainKHR()", pCreateInfo, surface_state, old_swapchain_state)) {
10526261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski        return VK_ERROR_VALIDATION_FAILED_EXT;
10527261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski    }
10528261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski
10529261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski    VkResult result = dev_data->dispatch_table.CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain);
10530261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski
10531261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski    PostCallRecordCreateSwapchainKHR(dev_data, result, pCreateInfo, pSwapchain, surface_state, old_swapchain_state);
10532ddc5201048319558ce66701163a4546ee957af19Chris Forbes
105335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
105345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
105355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10536bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks *pAllocator) {
1053756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
1053883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
105395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10540b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
105419a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto swapchain_data = GetSwapchainNode(dev_data, swapchain);
10542b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis    if (swapchain_data) {
10543b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis        if (swapchain_data->images.size() > 0) {
10544b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis            for (auto swapchain_image : swapchain_data->images) {
105455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                auto image_sub = dev_data->imageSubresourceMap.find(swapchain_image);
105465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (image_sub != dev_data->imageSubresourceMap.end()) {
105475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    for (auto imgsubpair : image_sub->second) {
105485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        auto image_item = dev_data->imageLayoutMap.find(imgsubpair);
105495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        if (image_item != dev_data->imageLayoutMap.end()) {
105505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                            dev_data->imageLayoutMap.erase(image_item);
105515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        }
105525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
105535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    dev_data->imageSubresourceMap.erase(image_sub);
105545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
1055583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                skip_call =
10556f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                    ClearMemoryObjectBindings(dev_data, (uint64_t)swapchain_image, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT);
1055794c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis                dev_data->imageMap.erase(swapchain_image);
105585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
105595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
10560ddc5201048319558ce66701163a4546ee957af19Chris Forbes
105619a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto surface_state = GetSurfaceState(dev_data->instance_data, swapchain_data->createInfo.surface);
10562ddc5201048319558ce66701163a4546ee957af19Chris Forbes        if (surface_state) {
10563cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (surface_state->swapchain == swapchain_data) surface_state->swapchain = nullptr;
10564cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (surface_state->old_swapchain == swapchain_data) surface_state->old_swapchain = nullptr;
10565ddc5201048319558ce66701163a4546ee957af19Chris Forbes        }
10566ddc5201048319558ce66701163a4546ee957af19Chris Forbes
105675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->device_extensions.swapchainMap.erase(swapchain);
105685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10569b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
10570cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.DestroySwapchainKHR(device, swapchain, pAllocator);
105715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
105725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10573bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pCount,
10574bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                     VkImage *pSwapchainImages) {
1057556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
105764a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.GetSwapchainImagesKHR(device, swapchain, pCount, pSwapchainImages);
105775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
105785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS && pSwapchainImages != NULL) {
105795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // This should never happen and is checked by param checker.
10580cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!pCount) return result;
10581b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
105825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const size_t count = *pCount;
105839a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto swapchain_node = GetSwapchainNode(dev_data, swapchain);
10584b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis        if (swapchain_node && !swapchain_node->images.empty()) {
105850801763633180d277d26a90343464bd11646056fTobin Ehlis            // TODO : Not sure I like the memcmp here, but it works
105860801763633180d277d26a90343464bd11646056fTobin Ehlis            const bool mismatch = (swapchain_node->images.size() != count ||
105870801763633180d277d26a90343464bd11646056fTobin Ehlis                                   memcmp(&swapchain_node->images[0], pSwapchainImages, sizeof(swapchain_node->images[0]) * count));
105885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (mismatch) {
105895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // TODO: Verify against Valid Usage section of extension
105905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
105915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        (uint64_t)swapchain, __LINE__, MEMTRACK_NONE, "SWAP_CHAIN",
10592414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                        "vkGetSwapchainInfoKHR(0x%" PRIx64
105935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        ", VK_SWAP_CHAIN_INFO_TYPE_PERSISTENT_IMAGES_KHR) returned mismatching data",
105945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        (uint64_t)(swapchain));
105955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
105965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
105975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < *pCount; ++i) {
105985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            IMAGE_LAYOUT_NODE image_layout_node;
105995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            image_layout_node.layout = VK_IMAGE_LAYOUT_UNDEFINED;
106005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            image_layout_node.format = swapchain_node->createInfo.imageFormat;
106016d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            // Add imageMap entries for each swapchain image
106026d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            VkImageCreateInfo image_ci = {};
106036d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.mipLevels = 1;
106046d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.arrayLayers = swapchain_node->createInfo.imageArrayLayers;
106056d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.usage = swapchain_node->createInfo.imageUsage;
106066d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.format = swapchain_node->createInfo.imageFormat;
1060741ebcb6b517b1de5ae456d46d866f5e84a96a2c5Tobin Ehlis            image_ci.samples = VK_SAMPLE_COUNT_1_BIT;
106086d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.extent.width = swapchain_node->createInfo.imageExtent.width;
106096d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.extent.height = swapchain_node->createInfo.imageExtent.height;
106106d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.sharingMode = swapchain_node->createInfo.imageSharingMode;
106111facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            dev_data->imageMap[pSwapchainImages[i]] = unique_ptr<IMAGE_STATE>(new IMAGE_STATE(pSwapchainImages[i], &image_ci));
106121facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            auto &image_state = dev_data->imageMap[pSwapchainImages[i]];
106131facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            image_state->valid = false;
10614e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis            image_state->binding.mem = MEMTRACKER_SWAP_CHAIN_IMAGE_KEY;
106155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            swapchain_node->images.push_back(pSwapchainImages[i]);
106165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            ImageSubresourcePair subpair = {pSwapchainImages[i], false, VkImageSubresource()};
106175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->imageSubresourceMap[pSwapchainImages[i]].push_back(subpair);
106185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->imageLayoutMap[subpair] = image_layout_node;
106195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->device_extensions.imageToSwapchainMap[pSwapchainImages[i]] = swapchain;
106205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
106215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
106225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
106235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
106245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1062589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo) {
1062656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
106275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool skip_call = false;
106285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
106296c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    std::lock_guard<std::mutex> lock(global_lock);
106309a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto queue_state = GetQueueState(dev_data, queue);
106311671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes
106326c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    for (uint32_t i = 0; i < pPresentInfo->waitSemaphoreCount; ++i) {
106339a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto pSemaphore = GetSemaphoreNode(dev_data, pPresentInfo->pWaitSemaphores[i]);
106346c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        if (pSemaphore && !pSemaphore->signaled) {
10635226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
10636226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS,
10637226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                 "DS", "Queue 0x%p is waiting on semaphore 0x%" PRIx64 " that has no way to be signaled.", queue,
10638226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                 reinterpret_cast<const uint64_t &>(pPresentInfo->pWaitSemaphores[i]));
106395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
106406c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    }
10641249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis
106426c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    for (uint32_t i = 0; i < pPresentInfo->swapchainCount; ++i) {
106439a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto swapchain_data = GetSwapchainNode(dev_data, pPresentInfo->pSwapchains[i]);
10644a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes        if (swapchain_data) {
10645a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes            if (pPresentInfo->pImageIndices[i] >= swapchain_data->images.size()) {
10646bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                skip_call |= log_msg(
10647bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
10648bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    reinterpret_cast<uint64_t const &>(pPresentInfo->pSwapchains[i]), __LINE__, DRAWSTATE_SWAPCHAIN_INVALID_IMAGE,
10649bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "DS", "vkQueuePresentKHR: Swapchain image index too large (%u). There are only %u images in this swapchain.",
10650bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    pPresentInfo->pImageIndices[i], (uint32_t)swapchain_data->images.size());
10651bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            } else {
10652a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                auto image = swapchain_data->images[pPresentInfo->pImageIndices[i]];
106539a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto image_state = GetImageState(dev_data, image);
106541facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis                skip_call |= ValidateImageMemoryIsValid(dev_data, image_state, "vkQueuePresentKHR()");
10655a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes
106561facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis                if (!image_state->acquired) {
10657bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    skip_call |= log_msg(
10658bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
10659bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        reinterpret_cast<uint64_t const &>(pPresentInfo->pSwapchains[i]), __LINE__,
10660bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        DRAWSTATE_SWAPCHAIN_IMAGE_NOT_ACQUIRED, "DS",
10661bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        "vkQueuePresentKHR: Swapchain image index %u has not been acquired.", pPresentInfo->pImageIndices[i]);
10662a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                }
10663a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes
10664a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                vector<VkImageLayout> layouts;
10665a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                if (FindLayouts(dev_data, image, layouts)) {
10666a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                    for (auto layout : layouts) {
10667a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                        if (layout != VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) {
10668a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                            skip_call |=
106692fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT,
106702fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                        reinterpret_cast<uint64_t &>(queue), __LINE__, VALIDATION_ERROR_01964, "DS",
106712fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                        "Images passed to present must be in layout "
106722fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                        "VK_IMAGE_LAYOUT_PRESENT_SRC_KHR but is in %s. %s",
106732fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                        string_VkImageLayout(layout), validation_error_map[VALIDATION_ERROR_01964]);
10674a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                        }
106755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
106765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
106775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
106781671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes
106791671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            // All physical devices and queue families are required to be able
106801671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            // to present to any native window on Android; require the
106811671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            // application to have established support on any other platform.
106821671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            if (!dev_data->instance_data->androidSurfaceExtensionEnabled) {
106839a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto surface_state = GetSurfaceState(dev_data->instance_data, swapchain_data->createInfo.surface);
106841671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                auto support_it = surface_state->gpu_queue_support.find({dev_data->physical_device, queue_state->queueFamilyIndex});
106851671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes
106861671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                if (support_it == surface_state->gpu_queue_support.end()) {
106871671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                    skip_call |=
106881671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
106891671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                                reinterpret_cast<uint64_t const &>(pPresentInfo->pSwapchains[i]), __LINE__,
10690cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                DRAWSTATE_SWAPCHAIN_UNSUPPORTED_QUEUE, "DS",
10691cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                "vkQueuePresentKHR: Presenting image without calling "
10692cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                "vkGetPhysicalDeviceSurfaceSupportKHR");
106931671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                } else if (!support_it->second) {
10694cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip_call |= log_msg(
10695cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
10696cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        reinterpret_cast<uint64_t const &>(pPresentInfo->pSwapchains[i]), __LINE__, VALIDATION_ERROR_01961, "DS",
10697cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "vkQueuePresentKHR: Presenting image on queue that cannot "
10698cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "present to this surface. %s",
10699cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        validation_error_map[VALIDATION_ERROR_01961]);
107001671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                }
107011671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            }
107025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
107035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
107045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
107056c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    if (skip_call) {
107066c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        return VK_ERROR_VALIDATION_FAILED_EXT;
107076c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    }
107086c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes
107094a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.QueuePresentKHR(queue, pPresentInfo);
107106c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes
107116c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    if (result != VK_ERROR_VALIDATION_FAILED_EXT) {
107126c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        // Semaphore waits occur before error generation, if the call reached
107136c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        // the ICD. (Confirm?)
107146c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        for (uint32_t i = 0; i < pPresentInfo->waitSemaphoreCount; ++i) {
107159a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, pPresentInfo->pWaitSemaphores[i]);
107169867daedbf52debc77d6568162ee21e071699b80Chris Forbes            if (pSemaphore) {
107179867daedbf52debc77d6568162ee21e071699b80Chris Forbes                pSemaphore->signaler.first = VK_NULL_HANDLE;
107186c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes                pSemaphore->signaled = false;
107196c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes            }
107206c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        }
107219867daedbf52debc77d6568162ee21e071699b80Chris Forbes
10722220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes        for (uint32_t i = 0; i < pPresentInfo->swapchainCount; ++i) {
10723220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            // Note: this is imperfect, in that we can get confused about what
10724220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            // did or didn't succeed-- but if the app does that, it's confused
10725220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            // itself just as much.
10726220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            auto local_result = pPresentInfo->pResults ? pPresentInfo->pResults[i] : result;
10727220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes
10728cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (local_result != VK_SUCCESS && local_result != VK_SUBOPTIMAL_KHR) continue;  // this present didn't actually happen.
10729220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes
10730220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            // Mark the image as having been released to the WSI
107319a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto swapchain_data = GetSwapchainNode(dev_data, pPresentInfo->pSwapchains[i]);
10732220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            auto image = swapchain_data->images[pPresentInfo->pImageIndices[i]];
107339a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto image_state = GetImageState(dev_data, image);
107341facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            image_state->acquired = false;
10735220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes        }
10736220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes
107379867daedbf52debc77d6568162ee21e071699b80Chris Forbes        // Note: even though presentation is directed to a queue, there is no
107389867daedbf52debc77d6568162ee21e071699b80Chris Forbes        // direct ordering between QP and subsequent work, so QP (and its
107399867daedbf52debc77d6568162ee21e071699b80Chris Forbes        // semaphore waits) /never/ participate in any completion proof.
107406c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    }
107411344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
107425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
107435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
107445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10745c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinskistatic bool PreCallValidateCreateSharedSwapchainsKHR(layer_data *dev_data, uint32_t swapchainCount,
10746c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                     const VkSwapchainCreateInfoKHR *pCreateInfos, VkSwapchainKHR *pSwapchains,
10747c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                     std::vector<SURFACE_STATE *> &surface_state,
10748c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                     std::vector<SWAPCHAIN_NODE *> &old_swapchain_state) {
107490342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    if (pCreateInfos) {
10750c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski        std::lock_guard<std::mutex> lock(global_lock);
107510342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        for (uint32_t i = 0; i < swapchainCount; i++) {
107529a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            surface_state.push_back(GetSurfaceState(dev_data->instance_data, pCreateInfos[i].surface));
107539a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            old_swapchain_state.push_back(GetSwapchainNode(dev_data, pCreateInfos[i].oldSwapchain));
107549ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            std::stringstream func_name;
107559ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            func_name << "vkCreateSharedSwapchainsKHR[" << swapchainCount << "]";
10756bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (PreCallValidateCreateSwapchainKHR(dev_data, func_name.str().c_str(), &pCreateInfos[i], surface_state[i],
10757bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                  old_swapchain_state[i])) {
10758c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                return true;
107590342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            }
107600342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        }
107610342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    }
10762c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    return false;
10763c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski}
107640342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski
10765c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinskistatic void PostCallRecordCreateSharedSwapchainsKHR(layer_data *dev_data, VkResult result, uint32_t swapchainCount,
10766c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                    const VkSwapchainCreateInfoKHR *pCreateInfos, VkSwapchainKHR *pSwapchains,
10767c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                    std::vector<SURFACE_STATE *> &surface_state,
10768c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                    std::vector<SWAPCHAIN_NODE *> &old_swapchain_state) {
107690342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    if (VK_SUCCESS == result) {
107700342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        for (uint32_t i = 0; i < swapchainCount; i++) {
107710342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            auto swapchain_state = unique_ptr<SWAPCHAIN_NODE>(new SWAPCHAIN_NODE(&pCreateInfos[i], pSwapchains[i]));
107720342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            surface_state[i]->swapchain = swapchain_state.get();
107730342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            dev_data->device_extensions.swapchainMap[pSwapchains[i]] = std::move(swapchain_state);
107740342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        }
107750342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    } else {
107760342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        for (uint32_t i = 0; i < swapchainCount; i++) {
107770342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            surface_state[i]->swapchain = nullptr;
107780342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        }
107790342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    }
107800342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    // Spec requires that even if CreateSharedSwapchainKHR fails, oldSwapchain behaves as replaced.
107810342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    for (uint32_t i = 0; i < swapchainCount; i++) {
107820342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        if (old_swapchain_state[i]) {
107830342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            old_swapchain_state[i]->replaced = true;
107840342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        }
107850342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        surface_state[i]->old_swapchain = old_swapchain_state[i];
107860342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    }
10787c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    return;
10788c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski}
10789c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski
10790c6cd632d064579a64e61d8704b411d0e4ace7adaMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateSharedSwapchainsKHR(VkDevice device, uint32_t swapchainCount,
10791c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                         const VkSwapchainCreateInfoKHR *pCreateInfos,
10792c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                         const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchains) {
1079356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
10794c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    std::vector<SURFACE_STATE *> surface_state;
10795c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    std::vector<SWAPCHAIN_NODE *> old_swapchain_state;
10796c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski
10797c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    if (PreCallValidateCreateSharedSwapchainsKHR(dev_data, swapchainCount, pCreateInfos, pSwapchains, surface_state,
10798c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                 old_swapchain_state)) {
10799c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski        return VK_ERROR_VALIDATION_FAILED_EXT;
10800c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    }
10801c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski
10802c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    VkResult result =
10803c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski        dev_data->dispatch_table.CreateSharedSwapchainsKHR(device, swapchainCount, pCreateInfos, pAllocator, pSwapchains);
10804c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski
10805c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    PostCallRecordCreateSharedSwapchainsKHR(dev_data, result, swapchainCount, pCreateInfos, pSwapchains, surface_state,
10806c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                            old_swapchain_state);
108070342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski
10808c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young    return result;
10809c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young}
10810c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young
1081189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL AcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout,
1081289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                   VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex) {
1081356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
1081483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
108151344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
10816b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
10817449670637ef4214b33018f497cf10daeff9dc85bChris Forbes
10818449670637ef4214b33018f497cf10daeff9dc85bChris Forbes    if (fence == VK_NULL_HANDLE && semaphore == VK_NULL_HANDLE) {
10819449670637ef4214b33018f497cf10daeff9dc85bChris Forbes        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
10820d17d86d15a733f1ec988956721ea4b7cdfb6771bChris Forbes                             reinterpret_cast<uint64_t &>(device), __LINE__, DRAWSTATE_SWAPCHAIN_NO_SYNC_FOR_ACQUIRE, "DS",
10821449670637ef4214b33018f497cf10daeff9dc85bChris Forbes                             "vkAcquireNextImageKHR: Semaphore and fence cannot both be VK_NULL_HANDLE. There would be no way "
10822449670637ef4214b33018f497cf10daeff9dc85bChris Forbes                             "to determine the completion of this operation.");
10823449670637ef4214b33018f497cf10daeff9dc85bChris Forbes    }
10824449670637ef4214b33018f497cf10daeff9dc85bChris Forbes
108259a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
10826f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    if (pSemaphore && pSemaphore->signaled) {
1082783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
108282fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                             reinterpret_cast<const uint64_t &>(semaphore), __LINE__, VALIDATION_ERROR_01952, "DS",
108292fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                             "vkAcquireNextImageKHR: Semaphore must not be currently signaled or in a wait state. %s",
108302fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                             validation_error_map[VALIDATION_ERROR_01952]);
108315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10832f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes
108339a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pFence = GetFenceNode(dev_data, fence);
10834f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    if (pFence) {
1083583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis        skip_call |= ValidateFenceForSubmit(dev_data, pFence);
108365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
108374a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes
108389a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto swapchain_data = GetSwapchainNode(dev_data, swapchain);
10839fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes
10840fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes    if (swapchain_data->replaced) {
10841fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
10842fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes                             reinterpret_cast<uint64_t &>(swapchain), __LINE__, DRAWSTATE_SWAPCHAIN_REPLACED, "DS",
10843fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes                             "vkAcquireNextImageKHR: This swapchain has been replaced. The application can still "
10844fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes                             "present any images it has acquired, but cannot acquire any more.");
10845fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes    }
10846fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes
108479a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(dev_data->instance_data, dev_data->physical_device);
108484a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes    if (physical_device_state->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState != UNCALLED) {
108496569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski        uint64_t acquired_images = std::count_if(swapchain_data->images.begin(), swapchain_data->images.end(),
108509a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                                                 [=](VkImage image) { return GetImageState(dev_data, image)->acquired; });
108514a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes        if (acquired_images > swapchain_data->images.size() - physical_device_state->surfaceCapabilities.minImageCount) {
108526569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski            skip_call |=
108536569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
108546569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski                        reinterpret_cast<uint64_t const &>(swapchain), __LINE__, DRAWSTATE_SWAPCHAIN_TOO_MANY_IMAGES, "DS",
108556569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski                        "vkAcquireNextImageKHR: Application has already acquired the maximum number of images (0x%" PRIxLEAST64 ")",
108566569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski                        acquired_images);
108574a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes        }
108584a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes    }
1085975269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis
1086075269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis    if (swapchain_data->images.size() == 0) {
1086175269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
1086275269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis                             reinterpret_cast<uint64_t const &>(swapchain), __LINE__, DRAWSTATE_SWAPCHAIN_IMAGES_NOT_FOUND, "DS",
1086375269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis                             "vkAcquireNextImageKHR: No images found to acquire from. Application probably did not call "
1086475269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis                             "vkGetSwapchainImagesKHR after swapchain creation.");
1086575269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis    }
1086675269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis
10867b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
108681344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
10869cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
10870f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes
108714a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.AcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, pImageIndex);
10872f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes
10873f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    lock.lock();
10874f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    if (result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR) {
10875f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        if (pFence) {
10876f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes            pFence->state = FENCE_INFLIGHT;
10877cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            pFence->signaler.first = VK_NULL_HANDLE;  // ANI isn't on a queue, so this can't participate in a completion proof.
10878f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        }
10879f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes
10880f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        // A successful call to AcquireNextImageKHR counts as a signal operation on semaphore
10881f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        if (pSemaphore) {
10882f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes            pSemaphore->signaled = true;
108839867daedbf52debc77d6568162ee21e071699b80Chris Forbes            pSemaphore->signaler.first = VK_NULL_HANDLE;
10884f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        }
10885220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes
10886220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes        // Mark the image as acquired.
10887220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes        auto image = swapchain_data->images[*pImageIndex];
108889a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto image_state = GetImageState(dev_data, image);
108891facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        image_state->acquired = true;
108905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10891f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    lock.unlock();
108921344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
108935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
108945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
108955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10896f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount,
10897f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski                                                        VkPhysicalDevice *pPhysicalDevices) {
1089883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
1089956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
10900bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    assert(instance_data);
10901219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes
10902bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    // For this instance, flag when vkEnumeratePhysicalDevices goes to QUERY_COUNT and then QUERY_DETAILS
10903bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    if (NULL == pPhysicalDevices) {
10904bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        instance_data->vkEnumeratePhysicalDevicesState = QUERY_COUNT;
10905f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    } else {
10906bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        if (UNCALLED == instance_data->vkEnumeratePhysicalDevicesState) {
10907bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            // Flag warning here. You can call this without having queried the count, but it may not be
10908bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            // robust on platforms with multiple physical devices.
10909bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            skip_call |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
10910bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis                                 VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, 0, __LINE__, DEVLIMITS_MISSING_QUERY_COUNT, "DL",
10911bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis                                 "Call sequence has vkEnumeratePhysicalDevices() w/ non-NULL pPhysicalDevices. You should first "
10912bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis                                 "call vkEnumeratePhysicalDevices() w/ NULL pPhysicalDevices to query pPhysicalDeviceCount.");
10913cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }  // TODO : Could also flag a warning if re-calling this function in QUERY_DETAILS state
10914bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        else if (instance_data->physical_devices_count != *pPhysicalDeviceCount) {
10915bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            // Having actual count match count from app is not a requirement, so this can be a warning
10916bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            skip_call |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
10917bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis                                 VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVLIMITS_COUNT_MISMATCH, "DL",
10918bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis                                 "Call to vkEnumeratePhysicalDevices() w/ pPhysicalDeviceCount value %u, but actual count "
10919bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis                                 "supported by this instance is %u.",
10920bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis                                 *pPhysicalDeviceCount, instance_data->physical_devices_count);
10921bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        }
10922bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        instance_data->vkEnumeratePhysicalDevicesState = QUERY_DETAILS;
10923f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    }
10924bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    if (skip_call) {
10925bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        return VK_ERROR_VALIDATION_FAILED_EXT;
10926bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    }
10927bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    VkResult result = instance_data->dispatch_table.EnumeratePhysicalDevices(instance, pPhysicalDeviceCount, pPhysicalDevices);
10928bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    if (NULL == pPhysicalDevices) {
10929bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        instance_data->physical_devices_count = *pPhysicalDeviceCount;
10930cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    } else if (result == VK_SUCCESS) {  // Save physical devices
10931bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        for (uint32_t i = 0; i < *pPhysicalDeviceCount; i++) {
10932bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            auto &phys_device_state = instance_data->physical_device_map[pPhysicalDevices[i]];
10933bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            phys_device_state.phys_device = pPhysicalDevices[i];
10934bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            // Init actual features for each physical device
10935bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            instance_data->dispatch_table.GetPhysicalDeviceFeatures(pPhysicalDevices[i], &phys_device_state.features);
10936bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        }
10937bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    }
10938bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    return result;
10939f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski}
10940f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
1094143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis// Common function to handle validation for GetPhysicalDeviceQueueFamilyProperties & 2KHR version
1094243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic bool ValidateCommonGetPhysicalDeviceQueueFamilyProperties(instance_layer_data *instance_data,
1094343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                 PHYSICAL_DEVICE_STATE *pd_state,
1094443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                 uint32_t *pQueueFamilyPropertyCount, bool qfp_null,
1094543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                 const char *count_var_name, const char *caller_name) {
1094643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    bool skip = false;
1094743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    if (qfp_null) {
1094843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        pd_state->vkGetPhysicalDeviceQueueFamilyPropertiesState = QUERY_COUNT;
1094943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    } else {
1095043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        // Verify that for each physical device, this function is called first with NULL pQueueFamilyProperties ptr in order to get
1095143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        // count
1095243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        if (UNCALLED == pd_state->vkGetPhysicalDeviceQueueFamilyPropertiesState) {
1095343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
1095443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                            VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVLIMITS_MISSING_QUERY_COUNT, "DL",
1095543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                            "Call sequence has %s() w/ non-NULL "
1095643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                            "pQueueFamilyProperties. You should first call %s() w/ "
1095743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                            "NULL pQueueFamilyProperties to query pCount.",
1095843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                            caller_name, caller_name);
1095943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        }
1096043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        // Then verify that pCount that is passed in on second call matches what was returned
1096143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        if (pd_state->queueFamilyPropertiesCount != *pQueueFamilyPropertyCount) {
1096243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            // TODO: this is not a requirement of the Valid Usage section for vkGetPhysicalDeviceQueueFamilyProperties, so
1096343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            // provide as warning
1096443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
1096543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                            VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVLIMITS_COUNT_MISMATCH, "DL",
1096643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                            "Call to %s() w/ %s value %u, but actual count supported by this physicalDevice is %u.", caller_name,
1096743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                            count_var_name, *pQueueFamilyPropertyCount, pd_state->queueFamilyPropertiesCount);
1096843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        }
1096943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        pd_state->vkGetPhysicalDeviceQueueFamilyPropertiesState = QUERY_DETAILS;
1097043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    }
1097143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    return skip;
1097243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1097343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1097443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic bool PreCallValidateGetPhysicalDeviceQueueFamilyProperties(instance_layer_data *instance_data,
1097543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                  PHYSICAL_DEVICE_STATE *pd_state, uint32_t *pCount,
1097643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                  VkQueueFamilyProperties *pQueueFamilyProperties) {
1097743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    return ValidateCommonGetPhysicalDeviceQueueFamilyProperties(instance_data, pd_state, pCount,
1097843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                (nullptr == pQueueFamilyProperties), "pCount",
1097943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                "vkGetPhysicalDeviceQueueFamilyProperties()");
1098043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1098143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1098243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic bool PreCallValidateGetPhysicalDeviceQueueFamilyProperties2KHR(instance_layer_data *instance_data,
1098343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                      PHYSICAL_DEVICE_STATE *pd_state,
1098443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                      uint32_t *pQueueFamilyPropertyCount,
1098543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                      VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
1098643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    return ValidateCommonGetPhysicalDeviceQueueFamilyProperties(instance_data, pd_state, pQueueFamilyPropertyCount,
1098743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                (nullptr == pQueueFamilyProperties), "pQueueFamilyPropertyCount",
1098843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                "vkGetPhysicalDeviceQueueFamilyProperties2KHR()");
1098943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1099043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1099143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis// Common function to update state for GetPhysicalDeviceQueueFamilyProperties & 2KHR version
1099243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic void StateUpdateCommonGetPhysicalDeviceQueueFamilyProperties(PHYSICAL_DEVICE_STATE *pd_state, uint32_t count,
1099343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                    VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
1099443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    if (!pQueueFamilyProperties) {
1099543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        pd_state->queueFamilyPropertiesCount = count;
1099643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    } else {  // Save queue family properties
1099743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        if (pd_state->queue_family_properties.size() < count) pd_state->queue_family_properties.resize(count);
1099843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        for (uint32_t i = 0; i < count; i++) {
1099943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            pd_state->queue_family_properties[i] = pQueueFamilyProperties[i].queueFamilyProperties;
1100043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        }
1100143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    }
1100243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1100343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1100443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic void PostCallRecordGetPhysicalDeviceQueueFamilyProperties(PHYSICAL_DEVICE_STATE *pd_state, uint32_t count,
1100543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                 VkQueueFamilyProperties *pQueueFamilyProperties) {
1100643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    VkQueueFamilyProperties2KHR *pqfp = nullptr;
1100743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    std::vector<VkQueueFamilyProperties2KHR> qfp;
1100843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    qfp.resize(count);
1100943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    if (pQueueFamilyProperties) {
1101043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        for (uint32_t i = 0; i < count; ++i) {
1101143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            qfp[i].sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR;
1101243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            qfp[i].pNext = nullptr;
1101343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            qfp[i].queueFamilyProperties = pQueueFamilyProperties[i];
1101443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        }
1101543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        pqfp = qfp.data();
1101643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    }
1101743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    StateUpdateCommonGetPhysicalDeviceQueueFamilyProperties(pd_state, count, pqfp);
1101843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1101943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1102043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic void PostCallRecordGetPhysicalDeviceQueueFamilyProperties2KHR(PHYSICAL_DEVICE_STATE *pd_state, uint32_t count,
1102143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                     VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
1102243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    StateUpdateCommonGetPhysicalDeviceQueueFamilyProperties(pd_state, count, pQueueFamilyProperties);
1102343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1102443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
11025bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
11026bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                  VkQueueFamilyProperties *pQueueFamilyProperties) {
1102756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
110289a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
1102943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    assert(physical_device_state);
1103043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    bool skip =
1103143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        PreCallValidateGetPhysicalDeviceQueueFamilyProperties(instance_data, physical_device_state, pCount, pQueueFamilyProperties);
1103243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    if (skip) {
1103343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        return;
1103443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    }
1103543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, pCount, pQueueFamilyProperties);
1103643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    PostCallRecordGetPhysicalDeviceQueueFamilyProperties(physical_device_state, *pCount, pQueueFamilyProperties);
1103743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1103843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1103943947a6175e3e942e04d902f4d18928168e2d0dbTobin EhlisVKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceQueueFamilyProperties2KHR(VkPhysicalDevice physicalDevice,
1104043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                      uint32_t *pQueueFamilyPropertyCount,
1104143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                      VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
1104256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
110439a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
1104443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    assert(physical_device_state);
1104543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    bool skip = PreCallValidateGetPhysicalDeviceQueueFamilyProperties2KHR(instance_data, physical_device_state,
1104643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                          pQueueFamilyPropertyCount, pQueueFamilyProperties);
1104743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    if (skip) {
1104843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        return;
11049cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski    }
1105043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties2KHR(physicalDevice, pQueueFamilyPropertyCount,
1105143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                             pQueueFamilyProperties);
1105243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    PostCallRecordGetPhysicalDeviceQueueFamilyProperties2KHR(physical_device_state, *pQueueFamilyPropertyCount,
1105343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                             pQueueFamilyProperties);
11054cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski}
11055cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski
11056bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskitemplate <typename TCreateInfo, typename FPtr>
11057bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic VkResult CreateSurface(VkInstance instance, TCreateInfo const *pCreateInfo, VkAllocationCallbacks const *pAllocator,
11058bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                              VkSurfaceKHR *pSurface, FPtr fptr) {
1105956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
11060747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11061747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    // Call down the call chain:
11062747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    VkResult result = (instance_data->dispatch_table.*fptr)(instance, pCreateInfo, pAllocator, pSurface);
11063747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11064747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    if (result == VK_SUCCESS) {
11065747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        std::unique_lock<std::mutex> lock(global_lock);
11066747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        instance_data->surface_map[*pSurface] = SURFACE_STATE(*pSurface);
11067747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        lock.unlock();
11068747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
11069747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11070747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return result;
11071747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11072747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11073747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR void VKAPI_CALL DestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks *pAllocator) {
11074747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool skip_call = false;
1107556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
11076747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
110779a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto surface_state = GetSurfaceState(instance_data, surface);
11078747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11079747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    if (surface_state) {
11080747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        // TODO: track swapchains created from this surface.
11081747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        instance_data->surface_map.erase(surface);
11082747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
11083747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    lock.unlock();
11084747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11085747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    if (!skip_call) {
11086747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        // Call down the call chain:
11087747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        instance_data->dispatch_table.DestroySurfaceKHR(instance, surface, pAllocator);
11088747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
11089747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11090747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
110916f2ed666809272002a31b3b4f8adf6581cb41819Norbert NopperVKAPI_ATTR VkResult VKAPI_CALL CreateDisplayPlaneSurfaceKHR(VkInstance instance, const VkDisplaySurfaceCreateInfoKHR *pCreateInfo,
110926f2ed666809272002a31b3b4f8adf6581cb41819Norbert Nopper                                                            const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
110936f2ed666809272002a31b3b4f8adf6581cb41819Norbert Nopper    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateDisplayPlaneSurfaceKHR);
110946f2ed666809272002a31b3b4f8adf6581cb41819Norbert Nopper}
110956f2ed666809272002a31b3b4f8adf6581cb41819Norbert Nopper
11096747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_ANDROID_KHR
11097747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR *pCreateInfo,
11098747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                       const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
11099747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateAndroidSurfaceKHR);
11100747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11101cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_ANDROID_KHR
11102747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11103747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_MIR_KHR
11104747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateMirSurfaceKHR(VkInstance instance, const VkMirSurfaceCreateInfoKHR *pCreateInfo,
11105747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                   const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
11106747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateMirSurfaceKHR);
11107747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11108cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_MIR_KHR
11109747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11110747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WAYLAND_KHR
11111747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateWaylandSurfaceKHR(VkInstance instance, const VkWaylandSurfaceCreateInfoKHR *pCreateInfo,
11112747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                       const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
11113a9c6cc532ce0ef61d48d1419a96aae51b0e4c64aTobin Ehlis    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateWaylandSurfaceKHR);
11114747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11115cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_WAYLAND_KHR
11116747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11117747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WIN32_KHR
11118747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateWin32SurfaceKHR(VkInstance instance, const VkWin32SurfaceCreateInfoKHR *pCreateInfo,
11119747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                     const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
11120747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateWin32SurfaceKHR);
11121747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11122cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_WIN32_KHR
11123747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11124747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XCB_KHR
11125747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateXcbSurfaceKHR(VkInstance instance, const VkXcbSurfaceCreateInfoKHR *pCreateInfo,
11126747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                   const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
11127747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateXcbSurfaceKHR);
11128747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11129cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_XCB_KHR
11130747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11131747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XLIB_KHR
11132747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateXlibSurfaceKHR(VkInstance instance, const VkXlibSurfaceCreateInfoKHR *pCreateInfo,
11133bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                    const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
11134747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateXlibSurfaceKHR);
11135747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11136cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_XLIB_KHR
11137747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
1113840921785005eb449ec7c18229f0d84c879708b8aChris ForbesVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
1113940921785005eb449ec7c18229f0d84c879708b8aChris Forbes                                                                       VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) {
1114056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    auto instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
1114140921785005eb449ec7c18229f0d84c879708b8aChris Forbes
1114240921785005eb449ec7c18229f0d84c879708b8aChris Forbes    std::unique_lock<std::mutex> lock(global_lock);
111439a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
1114440921785005eb449ec7c18229f0d84c879708b8aChris Forbes    lock.unlock();
1114540921785005eb449ec7c18229f0d84c879708b8aChris Forbes
11146bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result =
11147bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        instance_data->dispatch_table.GetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, pSurfaceCapabilities);
1114840921785005eb449ec7c18229f0d84c879708b8aChris Forbes
1114940921785005eb449ec7c18229f0d84c879708b8aChris Forbes    if (result == VK_SUCCESS) {
1115040921785005eb449ec7c18229f0d84c879708b8aChris Forbes        physical_device_state->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState = QUERY_DETAILS;
1115140921785005eb449ec7c18229f0d84c879708b8aChris Forbes        physical_device_state->surfaceCapabilities = *pSurfaceCapabilities;
1115240921785005eb449ec7c18229f0d84c879708b8aChris Forbes    }
1115340921785005eb449ec7c18229f0d84c879708b8aChris Forbes
1115440921785005eb449ec7c18229f0d84c879708b8aChris Forbes    return result;
1115540921785005eb449ec7c18229f0d84c879708b8aChris Forbes}
1115640921785005eb449ec7c18229f0d84c879708b8aChris Forbes
11157418a8711f3301f3027a900bb45daaf0892f4e644Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex,
11158418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes                                                                  VkSurfaceKHR surface, VkBool32 *pSupported) {
1115956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    auto instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
11160418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
111619a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto surface_state = GetSurfaceState(instance_data, surface);
11162418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    lock.unlock();
11163418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes
11164bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result =
11165bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        instance_data->dispatch_table.GetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, surface, pSupported);
11166418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes
11167418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    if (result == VK_SUCCESS) {
111686569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski        surface_state->gpu_queue_support[{physicalDevice, queueFamilyIndex}] = (*pSupported != 0);
11169418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    }
11170418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes
11171418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    return result;
11172418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes}
11173418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes
111749e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
111759e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                                                                       uint32_t *pPresentModeCount,
111769e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                                                                       VkPresentModeKHR *pPresentModes) {
111779e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    bool skip_call = false;
1117856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    auto instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
111799e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
111809e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    // TODO: this isn't quite right. available modes may differ by surface AND physical device.
111819a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
11182bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto &call_state = physical_device_state->vkGetPhysicalDeviceSurfacePresentModesKHRState;
111839e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
111849e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    if (pPresentModes) {
111859e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        // Compare the preliminary value of *pPresentModeCount with the value this time:
11186bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto prev_mode_count = (uint32_t)physical_device_state->present_modes.size();
111879e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        switch (call_state) {
11188cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case UNCALLED:
111899e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                skip_call |= log_msg(
11190bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
11191cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    reinterpret_cast<uint64_t>(physicalDevice), __LINE__, DEVLIMITS_MUST_QUERY_COUNT, "DL",
11192cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "vkGetPhysicalDeviceSurfacePresentModesKHR() called with non-NULL pPresentModeCount; but no prior positive "
11193cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "value has been seen for pPresentModeCount.");
11194cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
11195cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
11196cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // both query count and query details
11197cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (*pPresentModeCount != prev_mode_count) {
11198cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip_call |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
11199cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
11200cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         reinterpret_cast<uint64_t>(physicalDevice), __LINE__, DEVLIMITS_COUNT_MISMATCH, "DL",
11201cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         "vkGetPhysicalDeviceSurfacePresentModesKHR() called with *pPresentModeCount (%u) that "
11202cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         "differs from the value "
11203cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         "(%u) that was returned when pPresentModes was NULL.",
11204cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         *pPresentModeCount, prev_mode_count);
11205cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
11206cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
112079e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
112089e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    }
112099e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    lock.unlock();
112109e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
11211cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
112129e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
11213bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result = instance_data->dispatch_table.GetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, pPresentModeCount,
11214bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                        pPresentModes);
112159e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
112169e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
112179e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        lock.lock();
112189e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
112199e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        if (*pPresentModeCount) {
11220cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (call_state < QUERY_COUNT) call_state = QUERY_COUNT;
112219e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            if (*pPresentModeCount > physical_device_state->present_modes.size())
112229e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                physical_device_state->present_modes.resize(*pPresentModeCount);
112239e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
112249e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        if (pPresentModes) {
11225cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (call_state < QUERY_DETAILS) call_state = QUERY_DETAILS;
112269e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            for (uint32_t i = 0; i < *pPresentModeCount; i++) {
112279e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                physical_device_state->present_modes[i] = pPresentModes[i];
112289e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            }
112299e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
112305faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    }
112315faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
112325faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    return result;
112335faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes}
112345faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
112355faa662f6859b01c72d79027abde363d5f10dcd7Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
112365faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                                                                  uint32_t *pSurfaceFormatCount,
112375faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                                                                  VkSurfaceFormatKHR *pSurfaceFormats) {
112385faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    bool skip_call = false;
1123956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    auto instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
112405faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
112419a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
11242bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto &call_state = physical_device_state->vkGetPhysicalDeviceSurfaceFormatsKHRState;
112435faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
112445faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    if (pSurfaceFormats) {
11245bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto prev_format_count = (uint32_t)physical_device_state->surface_formats.size();
112465faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
112475faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        switch (call_state) {
11248cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case UNCALLED:
11249cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // Since we haven't recorded a preliminary value of *pSurfaceFormatCount, that likely means that the application
11250cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // didn't
11251cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // previously call this function with a NULL value of pSurfaceFormats:
112525faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                skip_call |= log_msg(
11253bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
11254cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    reinterpret_cast<uint64_t>(physicalDevice), __LINE__, DEVLIMITS_MUST_QUERY_COUNT, "DL",
11255cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "vkGetPhysicalDeviceSurfaceFormatsKHR() called with non-NULL pSurfaceFormatCount; but no prior positive "
11256cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "value has been seen for pSurfaceFormats.");
11257cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
11258cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
11259cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (prev_format_count != *pSurfaceFormatCount) {
11260cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip_call |= log_msg(
11261cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
11262cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, reinterpret_cast<uint64_t>(physicalDevice), __LINE__,
11263cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        DEVLIMITS_COUNT_MISMATCH, "DL",
11264cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "vkGetPhysicalDeviceSurfaceFormatsKHR() called with non-NULL pSurfaceFormatCount, and with pSurfaceFormats "
11265cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "set "
11266cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "to "
11267cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "a value (%u) that is greater than the value (%u) that was returned when pSurfaceFormatCount was NULL.",
11268cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        *pSurfaceFormatCount, prev_format_count);
11269cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
11270cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
112719e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
112729e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    }
112735faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    lock.unlock();
112745faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
11275cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
112769e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
112775faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    // Call down the call chain:
112785faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    auto result = instance_data->dispatch_table.GetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, pSurfaceFormatCount,
112795faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                                                                                   pSurfaceFormats);
112805faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
112815faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
112825faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        lock.lock();
112835faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
112845faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        if (*pSurfaceFormatCount) {
11285cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (call_state < QUERY_COUNT) call_state = QUERY_COUNT;
112865faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            if (*pSurfaceFormatCount > physical_device_state->surface_formats.size())
112875faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                physical_device_state->surface_formats.resize(*pSurfaceFormatCount);
112885faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        }
112895faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        if (pSurfaceFormats) {
11290cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (call_state < QUERY_DETAILS) call_state = QUERY_DETAILS;
112915faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            for (uint32_t i = 0; i < *pSurfaceFormatCount; i++) {
112925faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                physical_device_state->surface_formats[i] = pSurfaceFormats[i];
112935faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            }
112945faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        }
112955faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    }
112969e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    return result;
112979e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes}
112989e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
11299bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateDebugReportCallbackEXT(VkInstance instance,
11300bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                            const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
11301bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                            const VkAllocationCallbacks *pAllocator,
11302bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                            VkDebugReportCallbackEXT *pMsgCallback) {
1130356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
113049172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    VkResult res = instance_data->dispatch_table.CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
113055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == res) {
11306b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
113078860b85a52096f9f9b28616bc37feed505497a54Chris Forbes        res = layer_create_msg_callback(instance_data->report_data, false, pCreateInfo, pAllocator, pMsgCallback);
113085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
113095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return res;
113105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
113115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11312bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT msgCallback,
1131389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                         const VkAllocationCallbacks *pAllocator) {
1131456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
113159172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    instance_data->dispatch_table.DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);
11316b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::lock_guard<std::mutex> lock(global_lock);
113178860b85a52096f9f9b28616bc37feed505497a54Chris Forbes    layer_destroy_msg_callback(instance_data->report_data, msgCallback, pAllocator);
113185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
113195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11320bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags,
11321bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 VkDebugReportObjectTypeEXT objType, uint64_t object, size_t location,
11322bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
1132356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
113249172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    instance_data->dispatch_table.DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, pMsg);
113255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
113265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11327bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties) {
11328a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return util_GetLayerProperties(1, &global_layer, pCount, pProperties);
11329a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu}
11330a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu
11331bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
11332bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                              VkLayerProperties *pProperties) {
11333a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return util_GetLayerProperties(1, &global_layer, pCount, pProperties);
11334a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu}
11335a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu
11336bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
11337bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                    VkExtensionProperties *pProperties) {
11338a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    if (pLayerName && !strcmp(pLayerName, global_layer.layerName))
11339a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu        return util_GetExtensionProperties(1, instance_extensions, pCount, pProperties);
11340a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu
11341a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return VK_ERROR_LAYER_NOT_PRESENT;
11342a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu}
11343a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu
11344bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char *pLayerName,
11345bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                  uint32_t *pCount, VkExtensionProperties *pProperties) {
11346cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (pLayerName && !strcmp(pLayerName, global_layer.layerName)) return util_GetExtensionProperties(0, NULL, pCount, pProperties);
11347a8f4a23b1e9c068717eda47cc583a93f447c77e3Chia-I Wu
11348a8f4a23b1e9c068717eda47cc583a93f447c77e3Chia-I Wu    assert(physicalDevice);
11349a8f4a23b1e9c068717eda47cc583a93f447c77e3Chia-I Wu
1135056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
113519172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    return instance_data->dispatch_table.EnumerateDeviceExtensionProperties(physicalDevice, NULL, pCount, pProperties);
1135208939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu}
1135308939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu
11354bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_core_instance_command(const char *name);
113557ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu
11356bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_core_device_command(const char *name);
1135780be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu
11358bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_khr_swapchain_command(const char *name, VkDevice dev);
1135909a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu
11360bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_khr_surface_command(const char *name, VkInstance instance);
11361747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11362bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_extension_instance_commands(const char *name, VkInstance instance);
11363b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
1136489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice dev, const char *funcName) {
1136580be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    PFN_vkVoidFunction proc = intercept_core_device_command(funcName);
11366cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (proc) return proc;
1136780be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu
1136880be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    assert(dev);
113695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1137009a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu    proc = intercept_khr_swapchain_command(funcName, dev);
11371cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (proc) return proc;
1137209a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu
1137356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(dev), layer_data_map);
113745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
113754a0754042cf090e131e9e769d8a3633c228625beChris Forbes    auto &table = dev_data->dispatch_table;
11376cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!table.GetDeviceProcAddr) return nullptr;
113774a0754042cf090e131e9e769d8a3633c228625beChris Forbes    return table.GetDeviceProcAddr(dev, funcName);
113785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
113795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1138089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetInstanceProcAddr(VkInstance instance, const char *funcName) {
113817ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    PFN_vkVoidFunction proc = intercept_core_instance_command(funcName);
11382cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!proc) proc = intercept_core_device_command(funcName);
11383cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!proc) proc = intercept_khr_swapchain_command(funcName, VK_NULL_HANDLE);
11384cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!proc) proc = intercept_khr_surface_command(funcName, instance);
11385cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (proc) return proc;
113865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
113877ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    assert(instance);
113885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1138956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
113908860b85a52096f9f9b28616bc37feed505497a54Chris Forbes    proc = debug_report_get_instance_proc_addr(instance_data->report_data, funcName);
11391cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (proc) return proc;
113925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11393b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    proc = intercept_extension_instance_commands(funcName, instance);
11394cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (proc) return proc;
11395b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
113964a0754042cf090e131e9e769d8a3633c228625beChris Forbes    auto &table = instance_data->dispatch_table;
11397cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!table.GetInstanceProcAddr) return nullptr;
113984a0754042cf090e131e9e769d8a3633c228625beChris Forbes    return table.GetInstanceProcAddr(instance, funcName);
113995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
1140008939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu
11401b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark YoungVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
11402b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    assert(instance);
11403b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
1140456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
11405b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11406b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    auto &table = instance_data->dispatch_table;
11407cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!table.GetPhysicalDeviceProcAddr) return nullptr;
11408b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    return table.GetPhysicalDeviceProcAddr(instance, funcName);
11409b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young}
11410b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11411bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_core_instance_command(const char *name) {
114127ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    static const struct {
114137ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu        const char *name;
114147ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu        PFN_vkVoidFunction proc;
114157ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    } core_instance_commands[] = {
11416bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkGetInstanceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetInstanceProcAddr)},
11417bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vk_layerGetPhysicalDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceProcAddr)},
11418bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkGetDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceProcAddr)},
11419bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkCreateInstance", reinterpret_cast<PFN_vkVoidFunction>(CreateInstance)},
11420bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkCreateDevice", reinterpret_cast<PFN_vkVoidFunction>(CreateDevice)},
11421bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkEnumeratePhysicalDevices", reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDevices)},
11422bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkGetPhysicalDeviceQueueFamilyProperties", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceQueueFamilyProperties)},
11423bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkDestroyInstance", reinterpret_cast<PFN_vkVoidFunction>(DestroyInstance)},
11424bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkEnumerateInstanceLayerProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceLayerProperties)},
11425bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkEnumerateDeviceLayerProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateDeviceLayerProperties)},
11426bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkEnumerateInstanceExtensionProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceExtensionProperties)},
11427bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkEnumerateDeviceExtensionProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateDeviceExtensionProperties)},
114287ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    };
114297ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu
114307ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    for (size_t i = 0; i < ARRAY_SIZE(core_instance_commands); i++) {
11431cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!strcmp(core_instance_commands[i].name, name)) return core_instance_commands[i].proc;
114327ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    }
114337ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu
114347ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    return nullptr;
114357ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu}
114367ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu
11437bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_core_device_command(const char *name) {
1143880be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    static const struct {
1143980be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu        const char *name;
1144080be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu        PFN_vkVoidFunction proc;
1144180be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    } core_device_commands[] = {
11442593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkGetDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceProcAddr)},
11443593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkQueueSubmit", reinterpret_cast<PFN_vkVoidFunction>(QueueSubmit)},
11444593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkWaitForFences", reinterpret_cast<PFN_vkVoidFunction>(WaitForFences)},
11445593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkGetFenceStatus", reinterpret_cast<PFN_vkVoidFunction>(GetFenceStatus)},
11446593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkQueueWaitIdle", reinterpret_cast<PFN_vkVoidFunction>(QueueWaitIdle)},
11447593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDeviceWaitIdle", reinterpret_cast<PFN_vkVoidFunction>(DeviceWaitIdle)},
11448593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkGetDeviceQueue", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceQueue)},
11449593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyInstance", reinterpret_cast<PFN_vkVoidFunction>(DestroyInstance)},
11450593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyDevice", reinterpret_cast<PFN_vkVoidFunction>(DestroyDevice)},
11451593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyFence", reinterpret_cast<PFN_vkVoidFunction>(DestroyFence)},
11452593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkResetFences", reinterpret_cast<PFN_vkVoidFunction>(ResetFences)},
11453593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroySemaphore", reinterpret_cast<PFN_vkVoidFunction>(DestroySemaphore)},
11454593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyEvent", reinterpret_cast<PFN_vkVoidFunction>(DestroyEvent)},
11455593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyQueryPool", reinterpret_cast<PFN_vkVoidFunction>(DestroyQueryPool)},
11456593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyBuffer", reinterpret_cast<PFN_vkVoidFunction>(DestroyBuffer)},
11457593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyBufferView", reinterpret_cast<PFN_vkVoidFunction>(DestroyBufferView)},
11458593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyImage", reinterpret_cast<PFN_vkVoidFunction>(DestroyImage)},
11459593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyImageView", reinterpret_cast<PFN_vkVoidFunction>(DestroyImageView)},
11460593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyShaderModule", reinterpret_cast<PFN_vkVoidFunction>(DestroyShaderModule)},
11461593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyPipeline", reinterpret_cast<PFN_vkVoidFunction>(DestroyPipeline)},
11462593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyPipelineLayout", reinterpret_cast<PFN_vkVoidFunction>(DestroyPipelineLayout)},
11463593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroySampler", reinterpret_cast<PFN_vkVoidFunction>(DestroySampler)},
11464593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyDescriptorSetLayout", reinterpret_cast<PFN_vkVoidFunction>(DestroyDescriptorSetLayout)},
11465593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(DestroyDescriptorPool)},
11466593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyFramebuffer", reinterpret_cast<PFN_vkVoidFunction>(DestroyFramebuffer)},
11467593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyRenderPass", reinterpret_cast<PFN_vkVoidFunction>(DestroyRenderPass)},
11468593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateBuffer", reinterpret_cast<PFN_vkVoidFunction>(CreateBuffer)},
11469593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateBufferView", reinterpret_cast<PFN_vkVoidFunction>(CreateBufferView)},
11470593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateImage", reinterpret_cast<PFN_vkVoidFunction>(CreateImage)},
11471593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateImageView", reinterpret_cast<PFN_vkVoidFunction>(CreateImageView)},
11472593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateFence", reinterpret_cast<PFN_vkVoidFunction>(CreateFence)},
11473593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreatePipelineCache", reinterpret_cast<PFN_vkVoidFunction>(CreatePipelineCache)},
11474593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyPipelineCache", reinterpret_cast<PFN_vkVoidFunction>(DestroyPipelineCache)},
11475593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkGetPipelineCacheData", reinterpret_cast<PFN_vkVoidFunction>(GetPipelineCacheData)},
11476593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkMergePipelineCaches", reinterpret_cast<PFN_vkVoidFunction>(MergePipelineCaches)},
11477593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateGraphicsPipelines", reinterpret_cast<PFN_vkVoidFunction>(CreateGraphicsPipelines)},
11478593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateComputePipelines", reinterpret_cast<PFN_vkVoidFunction>(CreateComputePipelines)},
11479593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateSampler", reinterpret_cast<PFN_vkVoidFunction>(CreateSampler)},
11480593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateDescriptorSetLayout", reinterpret_cast<PFN_vkVoidFunction>(CreateDescriptorSetLayout)},
11481593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreatePipelineLayout", reinterpret_cast<PFN_vkVoidFunction>(CreatePipelineLayout)},
11482593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(CreateDescriptorPool)},
11483593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkResetDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(ResetDescriptorPool)},
11484593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkAllocateDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(AllocateDescriptorSets)},
11485593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkFreeDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(FreeDescriptorSets)},
11486593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkUpdateDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(UpdateDescriptorSets)},
11487593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateCommandPool", reinterpret_cast<PFN_vkVoidFunction>(CreateCommandPool)},
11488593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyCommandPool", reinterpret_cast<PFN_vkVoidFunction>(DestroyCommandPool)},
11489593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkResetCommandPool", reinterpret_cast<PFN_vkVoidFunction>(ResetCommandPool)},
11490593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateQueryPool", reinterpret_cast<PFN_vkVoidFunction>(CreateQueryPool)},
11491593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkAllocateCommandBuffers", reinterpret_cast<PFN_vkVoidFunction>(AllocateCommandBuffers)},
11492593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkFreeCommandBuffers", reinterpret_cast<PFN_vkVoidFunction>(FreeCommandBuffers)},
11493593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkBeginCommandBuffer", reinterpret_cast<PFN_vkVoidFunction>(BeginCommandBuffer)},
11494593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkEndCommandBuffer", reinterpret_cast<PFN_vkVoidFunction>(EndCommandBuffer)},
11495593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkResetCommandBuffer", reinterpret_cast<PFN_vkVoidFunction>(ResetCommandBuffer)},
11496593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdBindPipeline", reinterpret_cast<PFN_vkVoidFunction>(CmdBindPipeline)},
11497593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetViewport", reinterpret_cast<PFN_vkVoidFunction>(CmdSetViewport)},
11498593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetScissor", reinterpret_cast<PFN_vkVoidFunction>(CmdSetScissor)},
11499593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetLineWidth", reinterpret_cast<PFN_vkVoidFunction>(CmdSetLineWidth)},
11500593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetDepthBias", reinterpret_cast<PFN_vkVoidFunction>(CmdSetDepthBias)},
11501593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetBlendConstants", reinterpret_cast<PFN_vkVoidFunction>(CmdSetBlendConstants)},
11502593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetDepthBounds", reinterpret_cast<PFN_vkVoidFunction>(CmdSetDepthBounds)},
11503593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetStencilCompareMask", reinterpret_cast<PFN_vkVoidFunction>(CmdSetStencilCompareMask)},
11504593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetStencilWriteMask", reinterpret_cast<PFN_vkVoidFunction>(CmdSetStencilWriteMask)},
11505593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetStencilReference", reinterpret_cast<PFN_vkVoidFunction>(CmdSetStencilReference)},
11506593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdBindDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(CmdBindDescriptorSets)},
11507593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdBindVertexBuffers", reinterpret_cast<PFN_vkVoidFunction>(CmdBindVertexBuffers)},
11508593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdBindIndexBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdBindIndexBuffer)},
11509593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdDraw", reinterpret_cast<PFN_vkVoidFunction>(CmdDraw)},
11510593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdDrawIndexed", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndexed)},
11511593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdDrawIndirect", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndirect)},
11512593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdDrawIndexedIndirect", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndexedIndirect)},
11513593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdDispatch", reinterpret_cast<PFN_vkVoidFunction>(CmdDispatch)},
11514593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdDispatchIndirect", reinterpret_cast<PFN_vkVoidFunction>(CmdDispatchIndirect)},
11515593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdCopyBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyBuffer)},
11516593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdCopyImage", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyImage)},
11517593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdBlitImage", reinterpret_cast<PFN_vkVoidFunction>(CmdBlitImage)},
11518593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdCopyBufferToImage", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyBufferToImage)},
11519593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdCopyImageToBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyImageToBuffer)},
11520593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdUpdateBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdUpdateBuffer)},
11521593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdFillBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdFillBuffer)},
11522593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdClearColorImage", reinterpret_cast<PFN_vkVoidFunction>(CmdClearColorImage)},
11523593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdClearDepthStencilImage", reinterpret_cast<PFN_vkVoidFunction>(CmdClearDepthStencilImage)},
11524593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdClearAttachments", reinterpret_cast<PFN_vkVoidFunction>(CmdClearAttachments)},
11525593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdResolveImage", reinterpret_cast<PFN_vkVoidFunction>(CmdResolveImage)},
11526b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski        {"vkGetImageSubresourceLayout", reinterpret_cast<PFN_vkVoidFunction>(GetImageSubresourceLayout) },
11527593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetEvent", reinterpret_cast<PFN_vkVoidFunction>(CmdSetEvent)},
11528593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdResetEvent", reinterpret_cast<PFN_vkVoidFunction>(CmdResetEvent)},
11529593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdWaitEvents", reinterpret_cast<PFN_vkVoidFunction>(CmdWaitEvents)},
11530593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdPipelineBarrier", reinterpret_cast<PFN_vkVoidFunction>(CmdPipelineBarrier)},
11531593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdBeginQuery", reinterpret_cast<PFN_vkVoidFunction>(CmdBeginQuery)},
11532593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdEndQuery", reinterpret_cast<PFN_vkVoidFunction>(CmdEndQuery)},
11533593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdResetQueryPool", reinterpret_cast<PFN_vkVoidFunction>(CmdResetQueryPool)},
11534593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdCopyQueryPoolResults", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyQueryPoolResults)},
11535593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdPushConstants", reinterpret_cast<PFN_vkVoidFunction>(CmdPushConstants)},
11536593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdWriteTimestamp", reinterpret_cast<PFN_vkVoidFunction>(CmdWriteTimestamp)},
11537593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateFramebuffer", reinterpret_cast<PFN_vkVoidFunction>(CreateFramebuffer)},
11538593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateShaderModule", reinterpret_cast<PFN_vkVoidFunction>(CreateShaderModule)},
11539593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CreateRenderPass)},
11540593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdBeginRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CmdBeginRenderPass)},
11541593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdNextSubpass", reinterpret_cast<PFN_vkVoidFunction>(CmdNextSubpass)},
11542593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdEndRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CmdEndRenderPass)},
11543593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdExecuteCommands", reinterpret_cast<PFN_vkVoidFunction>(CmdExecuteCommands)},
11544593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkSetEvent", reinterpret_cast<PFN_vkVoidFunction>(SetEvent)},
11545593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkMapMemory", reinterpret_cast<PFN_vkVoidFunction>(MapMemory)},
11546593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkUnmapMemory", reinterpret_cast<PFN_vkVoidFunction>(UnmapMemory)},
11547593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkFlushMappedMemoryRanges", reinterpret_cast<PFN_vkVoidFunction>(FlushMappedMemoryRanges)},
11548593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkInvalidateMappedMemoryRanges", reinterpret_cast<PFN_vkVoidFunction>(InvalidateMappedMemoryRanges)},
11549593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkAllocateMemory", reinterpret_cast<PFN_vkVoidFunction>(AllocateMemory)},
11550593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkFreeMemory", reinterpret_cast<PFN_vkVoidFunction>(FreeMemory)},
11551593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkBindBufferMemory", reinterpret_cast<PFN_vkVoidFunction>(BindBufferMemory)},
11552593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkGetBufferMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(GetBufferMemoryRequirements)},
11553593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkGetImageMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(GetImageMemoryRequirements)},
11554593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkGetQueryPoolResults", reinterpret_cast<PFN_vkVoidFunction>(GetQueryPoolResults)},
11555593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkBindImageMemory", reinterpret_cast<PFN_vkVoidFunction>(BindImageMemory)},
11556593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkQueueBindSparse", reinterpret_cast<PFN_vkVoidFunction>(QueueBindSparse)},
11557593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateSemaphore", reinterpret_cast<PFN_vkVoidFunction>(CreateSemaphore)},
11558593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateEvent", reinterpret_cast<PFN_vkVoidFunction>(CreateEvent)},
1155980be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    };
1156080be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu
1156180be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    for (size_t i = 0; i < ARRAY_SIZE(core_device_commands); i++) {
11562cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!strcmp(core_device_commands[i].name, name)) return core_device_commands[i].proc;
1156380be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    }
1156480be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu
1156580be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    return nullptr;
1156680be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu}
1156780be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu
11568bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_khr_swapchain_command(const char *name, VkDevice dev) {
1156909a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu    static const struct {
1157009a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu        const char *name;
1157109a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu        PFN_vkVoidFunction proc;
1157209a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu    } khr_swapchain_commands[] = {
11573bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkCreateSwapchainKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateSwapchainKHR)},
11574bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkDestroySwapchainKHR", reinterpret_cast<PFN_vkVoidFunction>(DestroySwapchainKHR)},
11575bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkGetSwapchainImagesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetSwapchainImagesKHR)},
11576bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkAcquireNextImageKHR", reinterpret_cast<PFN_vkVoidFunction>(AcquireNextImageKHR)},
11577bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkQueuePresentKHR", reinterpret_cast<PFN_vkVoidFunction>(QueuePresentKHR)},
1157809a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu    };
11579c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young    layer_data *dev_data = nullptr;
1158009a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu
115813f6f8132355ebdae2736b31fc20de2ac60a70310Chia-I Wu    if (dev) {
1158256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        dev_data = GetLayerDataPtr(get_dispatch_key(dev), layer_data_map);
11583cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!dev_data->device_extensions.wsi_enabled) return nullptr;
115843f6f8132355ebdae2736b31fc20de2ac60a70310Chia-I Wu    }
1158509a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu
1158609a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu    for (size_t i = 0; i < ARRAY_SIZE(khr_swapchain_commands); i++) {
11587cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!strcmp(khr_swapchain_commands[i].name, name)) return khr_swapchain_commands[i].proc;
1158809a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu    }
1158909a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu
11590c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young    if (dev_data) {
11591cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!dev_data->device_extensions.wsi_display_swapchain_enabled) return nullptr;
11592c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young    }
11593c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young
11594cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!strcmp("vkCreateSharedSwapchainsKHR", name)) return reinterpret_cast<PFN_vkVoidFunction>(CreateSharedSwapchainsKHR);
11595c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young
1159609a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu    return nullptr;
11597747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11598747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11599bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_khr_surface_command(const char *name, VkInstance instance) {
11600747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    static const struct {
11601747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        const char *name;
11602747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        PFN_vkVoidFunction proc;
11603747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        bool instance_layer_data::*enable;
11604747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    } khr_surface_commands[] = {
11605747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_ANDROID_KHR
11606747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        {"vkCreateAndroidSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateAndroidSurfaceKHR),
11607bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::androidSurfaceExtensionEnabled},
11608cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_ANDROID_KHR
11609747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_MIR_KHR
11610747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        {"vkCreateMirSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateMirSurfaceKHR),
11611bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::mirSurfaceExtensionEnabled},
11612cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_MIR_KHR
11613747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WAYLAND_KHR
11614747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        {"vkCreateWaylandSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateWaylandSurfaceKHR),
11615bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::waylandSurfaceExtensionEnabled},
11616cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_WAYLAND_KHR
11617747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WIN32_KHR
11618747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        {"vkCreateWin32SurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateWin32SurfaceKHR),
11619bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::win32SurfaceExtensionEnabled},
11620cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_WIN32_KHR
11621747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XCB_KHR
11622747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        {"vkCreateXcbSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateXcbSurfaceKHR),
11623bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::xcbSurfaceExtensionEnabled},
11624cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_XCB_KHR
11625747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XLIB_KHR
11626747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        {"vkCreateXlibSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateXlibSurfaceKHR),
11627bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::xlibSurfaceExtensionEnabled},
11628cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_XLIB_KHR
11629bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkCreateDisplayPlaneSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateDisplayPlaneSurfaceKHR),
11630bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::displayExtensionEnabled},
11631747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        {"vkDestroySurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(DestroySurfaceKHR),
11632bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::surfaceExtensionEnabled},
1163340921785005eb449ec7c18229f0d84c879708b8aChris Forbes        {"vkGetPhysicalDeviceSurfaceCapabilitiesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfaceCapabilitiesKHR),
11634bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::surfaceExtensionEnabled},
11635418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes        {"vkGetPhysicalDeviceSurfaceSupportKHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfaceSupportKHR),
11636bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::surfaceExtensionEnabled},
116379e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        {"vkGetPhysicalDeviceSurfacePresentModesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfacePresentModesKHR),
11638bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::surfaceExtensionEnabled},
116395faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        {"vkGetPhysicalDeviceSurfaceFormatsKHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfaceFormatsKHR),
11640bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::surfaceExtensionEnabled},
11641747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    };
11642747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11643747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    instance_layer_data *instance_data = nullptr;
11644747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    if (instance) {
1164556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
11646747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
11647747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11648747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    for (size_t i = 0; i < ARRAY_SIZE(khr_surface_commands); i++) {
11649747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(khr_surface_commands[i].name, name)) {
11650cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (instance_data && !(instance_data->*(khr_surface_commands[i].enable))) return nullptr;
11651747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            return khr_surface_commands[i].proc;
11652747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        }
11653747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
11654747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11655747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return nullptr;
1165609a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu}
1165709a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu
1165843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic PFN_vkVoidFunction intercept_extension_instance_commands(const char *name, VkInstance instance) {
1165943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    static const struct {
1166043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        const char *name;
1166143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        PFN_vkVoidFunction proc;
1166243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        bool instance_layer_data::*enable;
1166343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    } instance_extension_commands[] = {
1166443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        {"vkGetPhysicalDeviceQueueFamilyProperties2KHR",
1166543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis         reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceQueueFamilyProperties2KHR)},
1166643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    };
1166743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1166843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    for (size_t i = 0; i < ARRAY_SIZE(instance_extension_commands); i++) {
1166943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        if (!strcmp(instance_extension_commands[i].name, name)) {
1167043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            return instance_extension_commands[i].proc;
1167143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        }
1167243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    }
1167343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    return nullptr;
1167443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
11675b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11676cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski}  // namespace core_validation
11677d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11678d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu// vk_layer_logging.h expects these to be defined
11679d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11680bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugReportCallbackEXT(VkInstance instance,
11681bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                              const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
11682bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                              const VkAllocationCallbacks *pAllocator,
11683bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                              VkDebugReportCallbackEXT *pMsgCallback) {
1168489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu    return core_validation::CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
11685d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
11686d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11687bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT msgCallback,
11688bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                           const VkAllocationCallbacks *pAllocator) {
1168989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu    core_validation::DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);
11690d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
11691d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11692bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL vkDebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags,
11693bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   VkDebugReportObjectTypeEXT objType, uint64_t object, size_t location,
11694bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
1169589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu    core_validation::DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, pMsg);
11696d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
11697d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11698a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu// loader-layer interface v0, just wrappers since there is only a layer
11699d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11700bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
11701bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                      VkExtensionProperties *pProperties) {
11702a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return core_validation::EnumerateInstanceExtensionProperties(pLayerName, pCount, pProperties);
1170308939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu}
1170408939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu
11705bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties(uint32_t *pCount,
11706bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                  VkLayerProperties *pProperties) {
11707a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return core_validation::EnumerateInstanceLayerProperties(pCount, pProperties);
1170808939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu}
1170908939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu
11710bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
11711bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                VkLayerProperties *pProperties) {
11712a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    // the layer command handles VK_NULL_HANDLE just fine internally
11713a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    assert(physicalDevice == VK_NULL_HANDLE);
11714a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return core_validation::EnumerateDeviceLayerProperties(VK_NULL_HANDLE, pCount, pProperties);
11715d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
11716d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11717d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I WuVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
11718d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu                                                                                    const char *pLayerName, uint32_t *pCount,
11719d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu                                                                                    VkExtensionProperties *pProperties) {
11720a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    // the layer command handles VK_NULL_HANDLE just fine internally
11721a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    assert(physicalDevice == VK_NULL_HANDLE);
11722a8f4a23b1e9c068717eda47cc583a93f447c77e3Chia-I Wu    return core_validation::EnumerateDeviceExtensionProperties(VK_NULL_HANDLE, pLayerName, pCount, pProperties);
11723d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
11724d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11725d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I WuVK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev, const char *funcName) {
1172689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu    return core_validation::GetDeviceProcAddr(dev, funcName);
11727d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
11728d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11729d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I WuVK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) {
1173089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu    return core_validation::GetInstanceProcAddr(instance, funcName);
1173108939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu}
11732b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11733bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_layerGetPhysicalDeviceProcAddr(VkInstance instance,
11734bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                           const char *funcName) {
11735b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    return core_validation::GetPhysicalDeviceProcAddr(instance, funcName);
11736b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young}
11737b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11738b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark YoungVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct) {
11739b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    assert(pVersionStruct != NULL);
11740b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    assert(pVersionStruct->sType == LAYER_NEGOTIATE_INTERFACE_STRUCT);
11741b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11742b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    // Fill in the function pointers if our version is at least capable of having the structure contain them.
11743b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    if (pVersionStruct->loaderLayerInterfaceVersion >= 2) {
11744b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        pVersionStruct->pfnGetInstanceProcAddr = vkGetInstanceProcAddr;
11745b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        pVersionStruct->pfnGetDeviceProcAddr = vkGetDeviceProcAddr;
11746b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        pVersionStruct->pfnGetPhysicalDeviceProcAddr = vk_layerGetPhysicalDeviceProcAddr;
11747b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    }
11748b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11749b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    if (pVersionStruct->loaderLayerInterfaceVersion < CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
11750b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        core_validation::loader_layer_if_version = pVersionStruct->loaderLayerInterfaceVersion;
11751b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    } else if (pVersionStruct->loaderLayerInterfaceVersion > CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
11752b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        pVersionStruct->loaderLayerInterfaceVersion = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
11753b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    }
11754b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11755b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    return VK_SUCCESS;
11756b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young}
11757