core_validation.cpp revision 2664122d97c3f0a98b3e5d12833bbb20196ca837
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 Ehlis// fwd decls
1065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstruct shader_module;
1075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
108f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbesstruct instance_layer_data {
109d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    VkInstance instance = VK_NULL_HANDLE;
110d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    debug_report_data *report_data = nullptr;
1115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<VkDebugReportCallbackEXT> logging_callback;
1129172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    VkLayerInstanceDispatchTable dispatch_table;
1139172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes
114219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes    CALL_STATE vkEnumeratePhysicalDevicesState = UNCALLED;
115219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes    uint32_t physical_devices_count = 0;
116b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    CALL_STATE vkEnumeratePhysicalDeviceGroupsState = UNCALLED;
117b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    uint32_t physical_device_groups_count = 0;
118219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes    CHECK_DISABLED disabled = {};
119219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes
120f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes    unordered_map<VkPhysicalDevice, PHYSICAL_DEVICE_STATE> physical_device_map;
121747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    unordered_map<VkSurfaceKHR, SURFACE_STATE> surface_map;
122747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
123747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool surfaceExtensionEnabled = false;
124747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool displayExtensionEnabled = false;
125747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool androidSurfaceExtensionEnabled = false;
126747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool mirSurfaceExtensionEnabled = false;
127747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool waylandSurfaceExtensionEnabled = false;
128747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool win32SurfaceExtensionEnabled = false;
129747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool xcbSurfaceExtensionEnabled = false;
130747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool xlibSurfaceExtensionEnabled = false;
131f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes};
132f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes
133f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbesstruct layer_data {
134f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes    debug_report_data *report_data = nullptr;
1354a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkLayerDispatchTable dispatch_table;
13694c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis
137d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    devExts device_extensions = {};
138cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    unordered_set<VkQueue> queues;  // All queues under given device
1395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Global set of all cmdBuffers that are inFlight on this device
1405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_set<VkCommandBuffer> globalInFlightCmdBuffers;
1415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Layer specific data
142d31a44af6da568692a73201825459689c9431867Tobin Ehlis    unordered_map<VkSampler, unique_ptr<SAMPLER_STATE>> samplerMap;
14379fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis    unordered_map<VkImageView, unique_ptr<IMAGE_VIEW_STATE>> imageViewMap;
1441facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    unordered_map<VkImage, unique_ptr<IMAGE_STATE>> imageMap;
14539267c0c27b8f032f05a6747eb02d4508247fdc1Tobin Ehlis    unordered_map<VkBufferView, unique_ptr<BUFFER_VIEW_STATE>> bufferViewMap;
1465cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    unordered_map<VkBuffer, unique_ptr<BUFFER_STATE>> bufferMap;
1474c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    unordered_map<VkPipeline, PIPELINE_STATE *> pipelineMap;
1488d6a38de0389036581ada119e548180c614fe0efChris Forbes    unordered_map<VkCommandPool, COMMAND_POOL_NODE> commandPoolMap;
149a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis    unordered_map<VkDescriptorPool, DESCRIPTOR_POOL_STATE *> descriptorPoolMap;
150397d27da37095073c8b86f9ff5289d0a39ce486eTobin Ehlis    unordered_map<VkDescriptorSet, cvdescriptorset::DescriptorSet *> setMap;
151cb9ce9e05b8e939d3da35c64997c70049877f4feTobin Ehlis    unordered_map<VkDescriptorSetLayout, cvdescriptorset::DescriptorSetLayout *> descriptorSetLayoutMap;
1525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkPipelineLayout, PIPELINE_LAYOUT_NODE> pipelineLayoutMap;
15357fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    unordered_map<VkDeviceMemory, unique_ptr<DEVICE_MEM_INFO>> memObjMap;
1545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkFence, FENCE_NODE> fenceMap;
15536c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlis    unordered_map<VkQueue, QUEUE_STATE> queueMap;
1564710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis    unordered_map<VkEvent, EVENT_STATE> eventMap;
1575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<QueryObject, bool> queryToStateMap;
1585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkQueryPool, QUERY_POOL_NODE> queryPoolMap;
1595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkSemaphore, SEMAPHORE_NODE> semaphoreMap;
16072d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis    unordered_map<VkCommandBuffer, GLOBAL_CB_NODE *> commandBufferMap;
161c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    unordered_map<VkFramebuffer, unique_ptr<FRAMEBUFFER_STATE>> frameBufferMap;
1625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkImage, vector<ImageSubresourcePair>> imageSubresourceMap;
1635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> imageLayoutMap;
164127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis    unordered_map<VkRenderPass, unique_ptr<RENDER_PASS_STATE>> renderPassMap;
165918c283ac4f8c604b79abd0c8b5706d2a7352a34Chris Forbes    unordered_map<VkShaderModule, unique_ptr<shader_module>> shaderModuleMap;
1666246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    unordered_map<VkDescriptorUpdateTemplateKHR, unique_ptr<TEMPLATE_STATE>> desc_template_map;
16707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
168d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    VkDevice device = VK_NULL_HANDLE;
169ec85232c4d8d9ddf7d2ae57cb8203c5ab52c1106Mark Lobodzinski    VkPhysicalDevice physical_device = VK_NULL_HANDLE;
1705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
171cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    instance_layer_data *instance_data = nullptr;  // from device to enclosing instance
17207a464bd7fec9583f346b8c4b8d43c88d2e9ffa4Chris Forbes
173f71dd305f197826a61f398bff725267a20ea1d90Chris Forbes    VkPhysicalDeviceFeatures enabled_features = {};
1745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Device specific data
175d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    PHYS_DEV_PROPERTIES_NODE phys_dev_properties = {};
176d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    VkPhysicalDeviceMemoryProperties phys_dev_mem_props = {};
177e47dbc3f3340fa177d877a67b2adb76a570027e5Mark Lobodzinski    VkPhysicalDeviceProperties phys_dev_props = {};
1785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis};
1795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
180b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis// TODO : Do we need to guard access to layer_data_map w/ lock?
181b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlisstatic unordered_map<void *, layer_data *> layer_data_map;
182f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbesstatic unordered_map<void *, instance_layer_data *> instance_layer_data_map;
183b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis
184b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Youngstatic uint32_t loader_layer_if_version = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
185b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
186e11120777bcd1543455d1de54b89292879bcd2bbChia-I Wustatic const VkLayerProperties global_layer = {
187f1ea418f193d10a8455cdf47e0eeeeb1f4d8b5bfJon Ashburn    "VK_LAYER_LUNARG_core_validation", VK_LAYER_API_VERSION, 1, "LunarG Validation Layer",
188e11120777bcd1543455d1de54b89292879bcd2bbChia-I Wu};
1895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
190cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskitemplate <class TCreateInfo>
191cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskivoid ValidateLayerOrdering(const TCreateInfo &createInfo) {
1925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool foundLayer = false;
1935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < createInfo.enabledLayerCount; ++i) {
194e11120777bcd1543455d1de54b89292879bcd2bbChia-I Wu        if (!strcmp(createInfo.ppEnabledLayerNames[i], global_layer.layerName)) {
1955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            foundLayer = true;
1965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
1975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // This has to be logged to console as we don't have a callback at this point.
1985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!foundLayer && !strcmp(createInfo.ppEnabledLayerNames[0], "VK_LAYER_GOOGLE_unique_objects")) {
199bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            LOGCONSOLE("Cannot activate layer VK_LAYER_GOOGLE_unique_objects prior to activating %s.", global_layer.layerName);
2005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
2015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
2035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Code imported from shader_checker
2055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic void build_def_index(shader_module *);
2065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// A forward iterator over spirv instructions. Provides easy access to len, opcode, and content words
2085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// without the caller needing to care too much about the physical SPIRV module layout.
2095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstruct spirv_inst_iter {
2105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<uint32_t>::const_iterator zero;
2115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<uint32_t>::const_iterator it;
2125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
213b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes    uint32_t len() {
214b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes        auto result = *it >> 16;
215b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes        assert(result > 0);
216b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes        return result;
217b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes    }
218b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes
2195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t opcode() { return *it & 0x0ffffu; }
220b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes
221b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes    uint32_t const &word(unsigned n) {
222b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes        assert(n < len());
223b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes        return it[n];
224b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes    }
225b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes
2265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t offset() { return (uint32_t)(it - zero); }
2275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter() {}
2295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter(std::vector<uint32_t>::const_iterator zero, std::vector<uint32_t>::const_iterator it) : zero(zero), it(it) {}
2315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool operator==(spirv_inst_iter const &other) { return it == other.it; }
2335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool operator!=(spirv_inst_iter const &other) { return it != other.it; }
2355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
236cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    spirv_inst_iter operator++(int) {  // x++
2375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        spirv_inst_iter ii = *this;
2385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        it += len();
2395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return ii;
2405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
242cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    spirv_inst_iter operator++() {  // ++x;
2435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        it += len();
2445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return *this;
2455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
24725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // The iterator and the value are the same thing.
2485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter &operator*() { return *this; }
2495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter const &operator*() const { return *this; }
2505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis};
2515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstruct shader_module {
25325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // The spirv image itself
2545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    vector<uint32_t> words;
25525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // A mapping of <id> to the first word of its def. this is useful because walking type
25625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // trees, constant expressions, etc requires jumping all over the instruction stream.
2575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<unsigned, unsigned> def_index;
258c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski    bool has_valid_spirv;
2595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    shader_module(VkShaderModuleCreateInfo const *pCreateInfo)
2615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        : words((uint32_t *)pCreateInfo->pCode, (uint32_t *)pCreateInfo->pCode + pCreateInfo->codeSize / sizeof(uint32_t)),
262c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski          def_index(),
263c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski          has_valid_spirv(true) {
2645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        build_def_index(this);
2655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
267c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski    shader_module() : has_valid_spirv(false) {}
268c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski
26925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Expose begin() / end() to enable range-based for
270cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    spirv_inst_iter begin() const { return spirv_inst_iter(words.begin(), words.begin() + 5); }  // First insn
271cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    spirv_inst_iter end() const { return spirv_inst_iter(words.begin(), words.end()); }          // Just past last insn
27225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Given an offset into the module, produce an iterator there.
2735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter at(unsigned offset) const { return spirv_inst_iter(words.begin(), words.begin() + offset); }
2745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Gets an iterator to the definition of an id
2765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter get_def(unsigned id) const {
2775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto it = def_index.find(id);
2785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (it == def_index.end()) {
2795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return end();
2805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
2815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return at(it->second);
2825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis};
2845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// TODO : This can be much smarter, using separate locks for separate global data
286b9e992386a44404152747d66817a733aa127e281Jeremy Hayesstatic std::mutex global_lock;
287593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
28879fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis// Return IMAGE_VIEW_STATE ptr for specified imageView or else NULL
2899a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisIMAGE_VIEW_STATE *GetImageViewState(const layer_data *dev_data, VkImageView image_view) {
2902c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    auto iv_it = dev_data->imageViewMap.find(image_view);
2912c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    if (iv_it == dev_data->imageViewMap.end()) {
2922c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis        return nullptr;
2932c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    }
2942c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    return iv_it->second.get();
2952c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis}
2969a55ca3674bb3fac3fbdfca9515a16a224aa9055Tobin Ehlis// Return sampler node ptr for specified sampler or else NULL
2979a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisSAMPLER_STATE *GetSamplerState(const layer_data *dev_data, VkSampler sampler) {
2982c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    auto sampler_it = dev_data->samplerMap.find(sampler);
2992c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    if (sampler_it == dev_data->samplerMap.end()) {
3009a55ca3674bb3fac3fbdfca9515a16a224aa9055Tobin Ehlis        return nullptr;
3019a55ca3674bb3fac3fbdfca9515a16a224aa9055Tobin Ehlis    }
3029a55ca3674bb3fac3fbdfca9515a16a224aa9055Tobin Ehlis    return sampler_it->second.get();
3039a55ca3674bb3fac3fbdfca9515a16a224aa9055Tobin Ehlis}
3045cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis// Return image state ptr for specified image or else NULL
3059a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisIMAGE_STATE *GetImageState(const layer_data *dev_data, VkImage image) {
3066d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis    auto img_it = dev_data->imageMap.find(image);
3076d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis    if (img_it == dev_data->imageMap.end()) {
3086d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis        return nullptr;
3096d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis    }
3106d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis    return img_it->second.get();
3116d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis}
3125cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis// Return buffer state ptr for specified buffer or else NULL
3139a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisBUFFER_STATE *GetBufferState(const layer_data *dev_data, VkBuffer buffer) {
3142c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    auto buff_it = dev_data->bufferMap.find(buffer);
3152c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    if (buff_it == dev_data->bufferMap.end()) {
3168718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis        return nullptr;
3178718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis    }
3188718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis    return buff_it->second.get();
3198718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis}
320b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis// Return swapchain node for specified swapchain or else NULL
3219a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisSWAPCHAIN_NODE *GetSwapchainNode(const layer_data *dev_data, VkSwapchainKHR swapchain) {
322b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis    auto swp_it = dev_data->device_extensions.swapchainMap.find(swapchain);
323b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis    if (swp_it == dev_data->device_extensions.swapchainMap.end()) {
324b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis        return nullptr;
325b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis    }
3263f687bf405355f3eec6bd1bc0e8d04daba37a0f9Tobin Ehlis    return swp_it->second.get();
327b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis}
328170dc65b45f6bcdec47e02b3aa19435e55b32804Tobin Ehlis// Return swapchain for specified image or else NULL
3299a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisVkSwapchainKHR GetSwapchainFromImage(const layer_data *dev_data, VkImage image) {
330170dc65b45f6bcdec47e02b3aa19435e55b32804Tobin Ehlis    auto img_it = dev_data->device_extensions.imageToSwapchainMap.find(image);
331170dc65b45f6bcdec47e02b3aa19435e55b32804Tobin Ehlis    if (img_it == dev_data->device_extensions.imageToSwapchainMap.end()) {
332170dc65b45f6bcdec47e02b3aa19435e55b32804Tobin Ehlis        return VK_NULL_HANDLE;
333170dc65b45f6bcdec47e02b3aa19435e55b32804Tobin Ehlis    }
334170dc65b45f6bcdec47e02b3aa19435e55b32804Tobin Ehlis    return img_it->second;
335170dc65b45f6bcdec47e02b3aa19435e55b32804Tobin Ehlis}
3362f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis// Return buffer node ptr for specified buffer or else NULL
3379a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisBUFFER_VIEW_STATE *GetBufferViewState(const layer_data *dev_data, VkBufferView buffer_view) {
33851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto bv_it = dev_data->bufferViewMap.find(buffer_view);
33951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (bv_it == dev_data->bufferViewMap.end()) {
3402f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis        return nullptr;
3412f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis    }
3422f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis    return bv_it->second.get();
3432f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis}
3448718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis
3459a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisFENCE_NODE *GetFenceNode(layer_data *dev_data, VkFence fence) {
34666fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    auto it = dev_data->fenceMap.find(fence);
34766fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    if (it == dev_data->fenceMap.end()) {
34866fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes        return nullptr;
34966fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    }
35066fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    return &it->second;
35166fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes}
35266fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes
3539a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisEVENT_STATE *GetEventNode(layer_data *dev_data, VkEvent event) {
3549556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis    auto it = dev_data->eventMap.find(event);
3559556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis    if (it == dev_data->eventMap.end()) {
3569556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis        return nullptr;
3579556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis    }
3589556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis    return &it->second;
3599556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis}
3609556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis
3619a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisQUERY_POOL_NODE *GetQueryPoolNode(layer_data *dev_data, VkQueryPool query_pool) {
362ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    auto it = dev_data->queryPoolMap.find(query_pool);
363ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    if (it == dev_data->queryPoolMap.end()) {
364ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis        return nullptr;
365ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    }
366ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    return &it->second;
367ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis}
368ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis
3699a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisQUEUE_STATE *GetQueueState(layer_data *dev_data, VkQueue queue) {
37066fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    auto it = dev_data->queueMap.find(queue);
37166fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    if (it == dev_data->queueMap.end()) {
37266fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes        return nullptr;
37366fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    }
37466fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    return &it->second;
37566fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes}
37666fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes
3779a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisSEMAPHORE_NODE *GetSemaphoreNode(layer_data *dev_data, VkSemaphore semaphore) {
3785e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes    auto it = dev_data->semaphoreMap.find(semaphore);
3795e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes    if (it == dev_data->semaphoreMap.end()) {
3805e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes        return nullptr;
3815e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes    }
3825e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes    return &it->second;
3835e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes}
3845e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes
3859a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisCOMMAND_POOL_NODE *GetCommandPoolNode(layer_data *dev_data, VkCommandPool pool) {
3868d6a38de0389036581ada119e548180c614fe0efChris Forbes    auto it = dev_data->commandPoolMap.find(pool);
3878d6a38de0389036581ada119e548180c614fe0efChris Forbes    if (it == dev_data->commandPoolMap.end()) {
3888d6a38de0389036581ada119e548180c614fe0efChris Forbes        return nullptr;
3898d6a38de0389036581ada119e548180c614fe0efChris Forbes    }
3908d6a38de0389036581ada119e548180c614fe0efChris Forbes    return &it->second;
3918d6a38de0389036581ada119e548180c614fe0efChris Forbes}
3923bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes
3939a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisPHYSICAL_DEVICE_STATE *GetPhysicalDeviceState(instance_layer_data *instance_data, VkPhysicalDevice phys) {
394f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes    auto it = instance_data->physical_device_map.find(phys);
395f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes    if (it == instance_data->physical_device_map.end()) {
3963bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes        return nullptr;
3973bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes    }
3983bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes    return &it->second;
3993bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes}
4003bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes
4019a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisSURFACE_STATE *GetSurfaceState(instance_layer_data *instance_data, VkSurfaceKHR surface) {
402747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    auto it = instance_data->surface_map.find(surface);
403747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    if (it == instance_data->surface_map.end()) {
404747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        return nullptr;
405747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
406747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return &it->second;
407747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
408747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
409f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis// Return ptr to memory binding for given handle of specified type
41051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic BINDABLE *GetObjectMemBinding(layer_data *dev_data, uint64_t handle, VkDebugReportObjectTypeEXT type) {
4115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (type) {
412cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT:
4139a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            return GetImageState(dev_data, VkImage(handle));
414cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT:
4159a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            return GetBufferState(dev_data, VkBuffer(handle));
416cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
417cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
4185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
41994c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis    return nullptr;
4205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
42172d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis// prototype
4229a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisGLOBAL_CB_NODE *GetCBNode(layer_data const *, const VkCommandBuffer);
42372d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis
4245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Return ptr to info in map container containing mem, or NULL if not found
4255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Calls to this function should be wrapped in mutex
4269a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisDEVICE_MEM_INFO *GetMemObjInfo(const layer_data *dev_data, const VkDeviceMemory mem) {
42757fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    auto mem_it = dev_data->memObjMap.find(mem);
42857fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    if (mem_it == dev_data->memObjMap.end()) {
4295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return NULL;
4305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
43157fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    return mem_it->second.get();
4325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
4335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
43451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void add_mem_obj_info(layer_data *dev_data, void *object, const VkDeviceMemory mem,
4355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                             const VkMemoryAllocateInfo *pAllocateInfo) {
4365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(object != NULL);
4375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
43851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    dev_data->memObjMap[mem] = unique_ptr<DEVICE_MEM_INFO>(new DEVICE_MEM_INFO(object, mem, pAllocateInfo));
4395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
440dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis
441dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis// Helper function to print lowercase string of object type
442dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis//  TODO: Unify string helper functions, this should really come out of a string helper if not there already
443dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlisstatic const char *object_type_to_string(VkDebugReportObjectTypeEXT type) {
444dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis    switch (type) {
445cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT:
446cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "image";
447cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT:
448cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "buffer";
449cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT:
450cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "image view";
451cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT:
452cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "buffer view";
453cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT:
454cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "swapchain";
455cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT:
456cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "descriptor set";
457cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT:
458cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "framebuffer";
459cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT:
460cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "event";
461cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT:
462cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "query pool";
463cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT:
464cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "descriptor pool";
465cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT:
466cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "command pool";
467cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT:
468cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "pipeline";
469cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT:
470cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "sampler";
471cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT:
472cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "renderpass";
473cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT:
474cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "device memory";
475cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT:
476cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "semaphore";
477cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
478cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "unknown";
479dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis    }
480dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis}
481dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis
482cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis// For given bound_object_handle, bound to given mem allocation, verify that the range for the bound object is valid
483f989de4217bce0f293121d0da53dc8328276370fTobin Ehlisstatic bool ValidateMemoryIsValid(layer_data *dev_data, VkDeviceMemory mem, uint64_t bound_object_handle,
484dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis                                  VkDebugReportObjectTypeEXT type, const char *functionName) {
4859a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
486f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    if (mem_info) {
487f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis        if (!mem_info->bound_ranges[bound_object_handle].valid) {
488f48a83f5b5548cd46a12770c7542ff902537ad3eKarl Schultz            return log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
489ea8e85ade623a09c601d939622cbd7740d8d66c9Tobin Ehlis                           reinterpret_cast<uint64_t &>(mem), __LINE__, MEMTRACK_INVALID_MEM_REGION, "MEM",
490dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis                           "%s: Cannot read invalid region of memory allocation 0x%" PRIx64 " for bound %s object 0x%" PRIx64
491dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis                           ", please fill the memory before using.",
492dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis                           functionName, reinterpret_cast<uint64_t &>(mem), object_type_to_string(type), bound_object_handle);
493f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis        }
494f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    }
495f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    return false;
496f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis}
4971facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis// For given image_state
4981facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis//  If mem is special swapchain key, then verify that image_state valid member is true
499f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis//  Else verify that the image's bound memory range is valid
50060568995aca225f81acda8ce40cfabbea2c19397Mark Lobodzinskibool ValidateImageMemoryIsValid(layer_data *dev_data, IMAGE_STATE *image_state, const char *functionName) {
501e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis    if (image_state->binding.mem == MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
5021facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        if (!image_state->valid) {
503f48a83f5b5548cd46a12770c7542ff902537ad3eKarl Schultz            return log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
504e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis                           reinterpret_cast<uint64_t &>(image_state->binding.mem), __LINE__, MEMTRACK_INVALID_MEM_REGION, "MEM",
505414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                           "%s: Cannot read invalid swapchain image 0x%" PRIx64 ", please fill the memory before using.",
5061facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis                           functionName, reinterpret_cast<uint64_t &>(image_state->image));
5075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
5085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
509e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis        return ValidateMemoryIsValid(dev_data, image_state->binding.mem, reinterpret_cast<uint64_t &>(image_state->image),
510dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis                                     VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, functionName);
5115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return false;
5135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
5145cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis// For given buffer_state, verify that the range it's bound to is valid
515c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinskibool ValidateBufferMemoryIsValid(layer_data *dev_data, BUFFER_STATE *buffer_state, const char *functionName) {
5165cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    return ValidateMemoryIsValid(dev_data, buffer_state->binding.mem, reinterpret_cast<uint64_t &>(buffer_state->buffer),
517dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis                                 VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, functionName);
518f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis}
519f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis// For the given memory allocation, set the range bound by the given handle object to the valid param value
520f989de4217bce0f293121d0da53dc8328276370fTobin Ehlisstatic void SetMemoryValid(layer_data *dev_data, VkDeviceMemory mem, uint64_t handle, bool valid) {
5219a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
522f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    if (mem_info) {
523f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis        mem_info->bound_ranges[handle].valid = valid;
524f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    }
525f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis}
526f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis// For given image node
5271facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis//  If mem is special swapchain key, then set entire image_state to valid param value
528f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis//  Else set the image's bound memory range to valid param value
529623784ad78c8b77a78c4db613db974c12e5f5a43Mark Lobodzinskivoid SetImageMemoryValid(layer_data *dev_data, IMAGE_STATE *image_state, bool valid) {
530e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis    if (image_state->binding.mem == MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
5311facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        image_state->valid = valid;
5325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
533e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis        SetMemoryValid(dev_data, image_state->binding.mem, reinterpret_cast<uint64_t &>(image_state->image), valid);
5345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
536f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis// For given buffer node set the buffer's bound memory range to valid param value
537c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinskivoid SetBufferMemoryValid(layer_data *dev_data, BUFFER_STATE *buffer_state, bool valid) {
5385cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    SetMemoryValid(dev_data, buffer_state->binding.mem, reinterpret_cast<uint64_t &>(buffer_state->buffer), valid);
539f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis}
5405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Find CB Info and add mem reference to list container
5415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Find Mem Obj Info and add CB reference to list container
542e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool update_cmd_buf_and_mem_references(layer_data *dev_data, const VkCommandBuffer cb, const VkDeviceMemory mem,
543e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                                              const char *apiName) {
54483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
5455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Skip validation if this image was created through WSI
5475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (mem != MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
5485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // First update CB binding in MemObj mini CB list
5499a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        DEVICE_MEM_INFO *pMemInfo = GetMemObjInfo(dev_data, mem);
5505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (pMemInfo) {
5515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Now update CBInfo's Mem reference list
5529a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            GLOBAL_CB_NODE *cb_node = GetCBNode(dev_data, cb);
553d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis            pMemInfo->cb_bindings.insert(cb_node);
5545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // TODO: keep track of all destroyed CBs so we know if this is a stale or simply invalid object
555d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis            if (cb_node) {
556d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                cb_node->memObjs.insert(mem);
5575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
5585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
5595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
56083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
5615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
562ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
56356f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis// Create binding link between given sampler and command buffer node
564d31a44af6da568692a73201825459689c9431867Tobin Ehlisvoid AddCommandBufferBindingSampler(GLOBAL_CB_NODE *cb_node, SAMPLER_STATE *sampler_state) {
565d31a44af6da568692a73201825459689c9431867Tobin Ehlis    sampler_state->cb_bindings.insert(cb_node);
566d31a44af6da568692a73201825459689c9431867Tobin Ehlis    cb_node->object_bindings.insert(
567d31a44af6da568692a73201825459689c9431867Tobin Ehlis        {reinterpret_cast<uint64_t &>(sampler_state->sampler), VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT});
56856f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis}
56956f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis
57056f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis// Create binding link between given image node and command buffer node
5711facd2c91911508b9fb61f54a56269841299f663Tobin Ehlisvoid AddCommandBufferBindingImage(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, IMAGE_STATE *image_state) {
572ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    // Skip validation if this image was created through WSI
573e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis    if (image_state->binding.mem != MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
574ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // First update CB binding in MemObj mini CB list
575d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis        for (auto mem_binding : image_state->GetBoundMemory()) {
5769a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            DEVICE_MEM_INFO *pMemInfo = GetMemObjInfo(dev_data, mem_binding);
577d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            if (pMemInfo) {
578d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis                pMemInfo->cb_bindings.insert(cb_node);
579d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis                // Now update CBInfo's Mem reference list
580d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis                cb_node->memObjs.insert(mem_binding);
581d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            }
582ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        }
583f940225c9e5e3e14b3f5a32d3ea360b585614600Tobin Ehlis        // Now update cb binding for image
5841facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        cb_node->object_bindings.insert({reinterpret_cast<uint64_t &>(image_state->image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT});
5851facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        image_state->cb_bindings.insert(cb_node);
586ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    }
587ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis}
588ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
58903ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis// Create binding link between given image view node and its image with command buffer node
59003ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlisvoid AddCommandBufferBindingImageView(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, IMAGE_VIEW_STATE *view_state) {
59103ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis    // First add bindings for imageView
59203ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis    view_state->cb_bindings.insert(cb_node);
59303ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis    cb_node->object_bindings.insert(
59403ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis        {reinterpret_cast<uint64_t &>(view_state->image_view), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT});
5959a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto image_state = GetImageState(dev_data, view_state->create_info.image);
59603ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis    // Add bindings for image within imageView
5971facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (image_state) {
5981facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        AddCommandBufferBindingImage(dev_data, cb_node, image_state);
59903ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis    }
60003ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis}
60103ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis
602ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis// Create binding link between given buffer node and command buffer node
6035cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlisvoid AddCommandBufferBindingBuffer(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, BUFFER_STATE *buffer_state) {
604ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    // First update CB binding in MemObj mini CB list
6055cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    for (auto mem_binding : buffer_state->GetBoundMemory()) {
6069a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        DEVICE_MEM_INFO *pMemInfo = GetMemObjInfo(dev_data, mem_binding);
607d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis        if (pMemInfo) {
608d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            pMemInfo->cb_bindings.insert(cb_node);
609d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            // Now update CBInfo's Mem reference list
610d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            cb_node->memObjs.insert(mem_binding);
611d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis        }
612ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    }
613ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    // Now update cb binding for buffer
6145cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    cb_node->object_bindings.insert({reinterpret_cast<uint64_t &>(buffer_state->buffer), VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT});
6155cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    buffer_state->cb_bindings.insert(cb_node);
616ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis}
617ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
61877b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis// Create binding link between given buffer view node and its buffer with command buffer node
61977b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlisvoid AddCommandBufferBindingBufferView(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, BUFFER_VIEW_STATE *view_state) {
62077b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis    // First add bindings for bufferView
62177b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis    view_state->cb_bindings.insert(cb_node);
62277b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis    cb_node->object_bindings.insert(
62377b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis        {reinterpret_cast<uint64_t &>(view_state->buffer_view), VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT});
6249a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto buffer_state = GetBufferState(dev_data, view_state->create_info.buffer);
62577b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis    // Add bindings for buffer within bufferView
6265cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (buffer_state) {
6275cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        AddCommandBufferBindingBuffer(dev_data, cb_node, buffer_state);
62877b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis    }
62977b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis}
63077b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis
631400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis// For every mem obj bound to particular CB, free bindings related to that CB
632d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlisstatic void clear_cmd_buf_and_mem_references(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
633d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis    if (cb_node) {
634d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis        if (cb_node->memObjs.size() > 0) {
635d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis            for (auto mem : cb_node->memObjs) {
6369a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                DEVICE_MEM_INFO *pInfo = GetMemObjInfo(dev_data, mem);
6375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (pInfo) {
638d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                    pInfo->cb_bindings.erase(cb_node);
6395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
6405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
641d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis            cb_node->memObjs.clear();
6425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
643d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis        cb_node->validate_functions.clear();
6445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
646400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis// Overloaded call to above function when GLOBAL_CB_NODE has not already been looked-up
647400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlisstatic void clear_cmd_buf_and_mem_references(layer_data *dev_data, const VkCommandBuffer cb) {
6489a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    clear_cmd_buf_and_mem_references(dev_data, GetCBNode(dev_data, cb));
6495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
6505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
651f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis// Clear a single object binding from given memory object, or report error if binding is missing
652f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlisstatic bool ClearMemoryObjectBinding(layer_data *dev_data, uint64_t handle, VkDebugReportObjectTypeEXT type, VkDeviceMemory mem) {
6539a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
654f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    // This obj is bound to a memory object. Remove the reference to this object in that memory object's list
655d4cd34fd49caa759cf01cafa5fa271401b17c3b9Jeremy Hayes    if (mem_info) {
656d4cd34fd49caa759cf01cafa5fa271401b17c3b9Jeremy Hayes        mem_info->obj_bindings.erase({handle, type});
657f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    }
658f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    return false;
659f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis}
660f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis
661f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis// ClearMemoryObjectBindings clears the binding of objects to memory
662f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis//  For the given object it pulls the memory bindings and makes sure that the bindings
663f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis//  no longer refer to the object being cleared. This occurs when objects are destroyed.
6648c59133586421be878d393799b30044497f77727Mark Lobodzinskibool ClearMemoryObjectBindings(layer_data *dev_data, uint64_t handle, VkDebugReportObjectTypeEXT type) {
665f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    bool skip = false;
666f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    BINDABLE *mem_binding = GetObjectMemBinding(dev_data, handle, type);
667f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    if (mem_binding) {
668f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        if (!mem_binding->sparse) {
669f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis            skip = ClearMemoryObjectBinding(dev_data, handle, type, mem_binding->binding.mem);
670cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        } else {  // Sparse, clear all bindings
671bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            for (auto &sparse_mem_binding : mem_binding->sparse_bindings) {
672f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                skip |= ClearMemoryObjectBinding(dev_data, handle, type, sparse_mem_binding.mem);
6735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
6745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
676f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    return skip;
6775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
6785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
679888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis// For given mem object, verify that it is not null or UNBOUND, if it is, report error. Return skip value.
680888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlisbool VerifyBoundMemoryIsValid(const layer_data *dev_data, VkDeviceMemory mem, uint64_t handle, const char *api_name,
68135ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                              const char *type_name, UNIQUE_VALIDATION_ERROR_CODE error_code) {
682888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    bool result = false;
683888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    if (VK_NULL_HANDLE == mem) {
684888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis        result = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, handle,
685cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                         __LINE__, error_code, "MEM", "%s: Vk%s object 0x%" PRIxLEAST64
686cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                      " used with no memory bound. Memory should be bound by calling "
687cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                      "vkBind%sMemory(). %s",
68835ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                         api_name, type_name, handle, type_name, validation_error_map[error_code]);
689888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    } else if (MEMORY_UNBOUND == mem) {
690888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis        result = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, handle,
691cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                         __LINE__, error_code, "MEM", "%s: Vk%s object 0x%" PRIxLEAST64
692cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                      " used with no memory bound and previously bound memory was freed. "
693cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                      "Memory must not be freed prior to this operation. %s",
69435ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                         api_name, type_name, handle, validation_error_map[error_code]);
695888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    }
696888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    return result;
697888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis}
698888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis
699b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski// Check to see if memory was ever bound to this image
70035ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlisbool ValidateMemoryIsBoundToImage(const layer_data *dev_data, const IMAGE_STATE *image_state, const char *api_name,
70135ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                                  UNIQUE_VALIDATION_ERROR_CODE error_code) {
702b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    bool result = false;
7031facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (0 == (static_cast<uint32_t>(image_state->createInfo.flags) & VK_IMAGE_CREATE_SPARSE_BINDING_BIT)) {
70435ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis        result = VerifyBoundMemoryIsValid(dev_data, image_state->binding.mem,
70535ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                                          reinterpret_cast<const uint64_t &>(image_state->image), api_name, "Image", error_code);
706b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    }
707b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    return result;
708b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski}
709b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski
710b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski// Check to see if memory was bound to this buffer
71135ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlisbool ValidateMemoryIsBoundToBuffer(const layer_data *dev_data, const BUFFER_STATE *buffer_state, const char *api_name,
71235ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                                   UNIQUE_VALIDATION_ERROR_CODE error_code) {
713b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    bool result = false;
7145cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (0 == (static_cast<uint32_t>(buffer_state->createInfo.flags) & VK_BUFFER_CREATE_SPARSE_BINDING_BIT)) {
7155cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        result = VerifyBoundMemoryIsValid(dev_data, buffer_state->binding.mem,
71635ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                                          reinterpret_cast<const uint64_t &>(buffer_state->buffer), api_name, "Buffer", error_code);
717b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    }
718b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    return result;
719b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski}
720b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski
7213a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// SetMemBinding is used to establish immutable, non-sparse binding between a single image/buffer object and memory object.
7223a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// Corresponding valid usage checks are in ValidateSetMemBinding().
723c18f059542c30f6b37f8a654df020be38adfade6Cort Strattonstatic void SetMemBinding(layer_data *dev_data, VkDeviceMemory mem, uint64_t handle, VkDebugReportObjectTypeEXT type,
724888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                          const char *apiName) {
725c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton    if (mem != VK_NULL_HANDLE) {
726c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        BINDABLE *mem_binding = GetObjectMemBinding(dev_data, handle, type);
727c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        assert(mem_binding);
728c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
729c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        if (mem_info) {
730c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton            mem_info->obj_bindings.insert({handle, type});
731c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton            // For image objects, make sure default memory state is correctly set
732c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton            // TODO : What's the best/correct way to handle this?
733c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton            if (VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT == type) {
734c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                auto const image_state = GetImageState(dev_data, VkImage(handle));
735c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                if (image_state) {
736c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                    VkImageCreateInfo ici = image_state->createInfo;
737c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                    if (ici.usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
738c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                        // TODO::  More memory state transition stuff.
739c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                    }
740c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                }
741c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton            }
742c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton            mem_binding->binding.mem = mem;
743c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        }
744c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton    }
745c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton}
7463a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton
7473a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// Valid usage checks for a call to SetMemBinding().
7483a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// For NULL mem case, output warning
7493a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// Make sure given object is in global object map
7503a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton//  IF a previous binding existed, output validation error
7513a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton//  Otherwise, add reference from objectInfo to memoryInfo
7523a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton//  Add reference off of objInfo
7533a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// TODO: We may need to refactor or pass in multiple valid usage statements to handle multiple valid usage conditions.
754c18f059542c30f6b37f8a654df020be38adfade6Cort Strattonstatic bool ValidateSetMemBinding(layer_data *dev_data, VkDeviceMemory mem, uint64_t handle, VkDebugReportObjectTypeEXT type,
755c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                                  const char *apiName) {
75683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
757f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    // It's an error to bind an object to NULL memory
758d3876b4ff7c293a14f73fe3622513d1fa91bf2d0Jeremy Hayes    if (mem != VK_NULL_HANDLE) {
759f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        BINDABLE *mem_binding = GetObjectMemBinding(dev_data, handle, type);
760888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis        assert(mem_binding);
76110ffe2d353eaff714ed92a2835af77d8b5042d31Cort        if (mem_binding->sparse) {
76210ffe2d353eaff714ed92a2835af77d8b5042d31Cort            UNIQUE_VALIDATION_ERROR_CODE error_code = VALIDATION_ERROR_00804;
76310ffe2d353eaff714ed92a2835af77d8b5042d31Cort            const char *handle_type = "IMAGE";
76474300755ed9ec780d6073af71e47f201217008d6Cort Stratton            if (strcmp(apiName, "vkBindBufferMemory()") == 0) {
76510ffe2d353eaff714ed92a2835af77d8b5042d31Cort                error_code = VALIDATION_ERROR_00792;
76610ffe2d353eaff714ed92a2835af77d8b5042d31Cort                handle_type = "BUFFER";
76710ffe2d353eaff714ed92a2835af77d8b5042d31Cort            } else {
76874300755ed9ec780d6073af71e47f201217008d6Cort Stratton                assert(strcmp(apiName, "vkBindImageMemory()") == 0);
76910ffe2d353eaff714ed92a2835af77d8b5042d31Cort            }
77010ffe2d353eaff714ed92a2835af77d8b5042d31Cort            skip_call |=
77110ffe2d353eaff714ed92a2835af77d8b5042d31Cort                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
77210ffe2d353eaff714ed92a2835af77d8b5042d31Cort                        reinterpret_cast<uint64_t &>(mem), __LINE__, error_code, "MEM",
77310ffe2d353eaff714ed92a2835af77d8b5042d31Cort                        "In %s, attempting to bind memory (0x%" PRIxLEAST64 ") to object (0x%" PRIxLEAST64
77410ffe2d353eaff714ed92a2835af77d8b5042d31Cort                        ") which was created with sparse memory flags (VK_%s_CREATE_SPARSE_*_BIT). %s",
77510ffe2d353eaff714ed92a2835af77d8b5042d31Cort                        apiName, reinterpret_cast<uint64_t &>(mem), handle, handle_type, validation_error_map[error_code]);
77610ffe2d353eaff714ed92a2835af77d8b5042d31Cort        }
7779a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
778888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis        if (mem_info) {
7799a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            DEVICE_MEM_INFO *prev_binding = GetMemObjInfo(dev_data, mem_binding->binding.mem);
780888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis            if (prev_binding) {
78198c2a17e1a549df84f4239f619bc0955f632cb43Cort                UNIQUE_VALIDATION_ERROR_CODE error_code = VALIDATION_ERROR_00803;
78274300755ed9ec780d6073af71e47f201217008d6Cort Stratton                if (strcmp(apiName, "vkBindBufferMemory()") == 0) {
78398c2a17e1a549df84f4239f619bc0955f632cb43Cort                    error_code = VALIDATION_ERROR_00791;
78498c2a17e1a549df84f4239f619bc0955f632cb43Cort                } else {
78574300755ed9ec780d6073af71e47f201217008d6Cort Stratton                    assert(strcmp(apiName, "vkBindImageMemory()") == 0);
78698c2a17e1a549df84f4239f619bc0955f632cb43Cort                }
787888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                skip_call |=
788888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
78998c2a17e1a549df84f4239f619bc0955f632cb43Cort                            reinterpret_cast<uint64_t &>(mem), __LINE__, error_code, "MEM",
790888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                            "In %s, attempting to bind memory (0x%" PRIxLEAST64 ") to object (0x%" PRIxLEAST64
79198c2a17e1a549df84f4239f619bc0955f632cb43Cort                            ") which has already been bound to mem object 0x%" PRIxLEAST64 ". %s",
79298c2a17e1a549df84f4239f619bc0955f632cb43Cort                            apiName, reinterpret_cast<uint64_t &>(mem), handle, reinterpret_cast<uint64_t &>(prev_binding->mem),
79398c2a17e1a549df84f4239f619bc0955f632cb43Cort                            validation_error_map[error_code]);
794f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis            } else if (mem_binding->binding.mem == MEMORY_UNBOUND) {
795888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                skip_call |=
796888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
797888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                            reinterpret_cast<uint64_t &>(mem), __LINE__, MEMTRACK_REBIND_OBJECT, "MEM",
798888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                            "In %s, attempting to bind memory (0x%" PRIxLEAST64 ") to object (0x%" PRIxLEAST64
799888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                            ") which was previous bound to memory that has since been freed. Memory bindings are immutable in "
800888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                            "Vulkan so this attempt to bind to new memory is not allowed.",
801888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis                            apiName, reinterpret_cast<uint64_t &>(mem), handle);
8025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
8035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
80583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
8065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
8075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// For NULL mem case, clear any previous binding Else...
8095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Make sure given object is in its object map
8105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  IF a previous binding existed, update binding
8115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Add reference from objectInfo to memoryInfo
8125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Add reference off of object's binding info
8130a1ce3dfd81c9f4efbe46f5ba5ddaea70bc4aa61Chris Forbes// Return VK_TRUE if addition is successful, VK_FALSE otherwise
814f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlisstatic bool SetSparseMemBinding(layer_data *dev_data, MEM_BINDING binding, uint64_t handle, VkDebugReportObjectTypeEXT type,
815f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                                const char *apiName) {
81683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = VK_FALSE;
8175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Handle NULL case separately, just clear previous binding & decrement reference
818f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    if (binding.mem == VK_NULL_HANDLE) {
819f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        // TODO : This should cause the range of the resource to be unbound according to spec
8205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
821f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        BINDABLE *mem_binding = GetObjectMemBinding(dev_data, handle, type);
822f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        assert(mem_binding);
823f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        assert(mem_binding->sparse);
8249a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, binding.mem);
825f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        if (mem_info) {
826f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis            mem_info->obj_bindings.insert({handle, type});
8272e415b757c1e43fda35311aad026af8d5c96681cTobin Ehlis            // Need to set mem binding for this object
828f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis            mem_binding->sparse_bindings.insert(binding);
8295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
83183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
832caf05e0db4959ae196ab34b024f352d9c0326870Tobin Ehlis}
833caf05e0db4959ae196ab34b024f352d9c0326870Tobin Ehlis
8345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Return a string representation of CMD_TYPE enum
8355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic string cmdTypeToString(CMD_TYPE cmd) {
8365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (cmd) {
837cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_BINDPIPELINE:
838cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_BINDPIPELINE";
839cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_BINDPIPELINEDELTA:
840cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_BINDPIPELINEDELTA";
841cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETVIEWPORTSTATE:
842cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETVIEWPORTSTATE";
843cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETLINEWIDTHSTATE:
844cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETLINEWIDTHSTATE";
845cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETDEPTHBIASSTATE:
846cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETDEPTHBIASSTATE";
847cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETBLENDSTATE:
848cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETBLENDSTATE";
849cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETDEPTHBOUNDSSTATE:
850cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETDEPTHBOUNDSSTATE";
851cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETSTENCILREADMASKSTATE:
852cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETSTENCILREADMASKSTATE";
853cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETSTENCILWRITEMASKSTATE:
854cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETSTENCILWRITEMASKSTATE";
855cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETSTENCILREFERENCESTATE:
856cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETSTENCILREFERENCESTATE";
857cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_BINDDESCRIPTORSETS:
858cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_BINDDESCRIPTORSETS";
859cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_BINDINDEXBUFFER:
860cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_BINDINDEXBUFFER";
861cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_BINDVERTEXBUFFER:
862cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_BINDVERTEXBUFFER";
863cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_DRAW:
864cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_DRAW";
865cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_DRAWINDEXED:
866cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_DRAWINDEXED";
867cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_DRAWINDIRECT:
868cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_DRAWINDIRECT";
869cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_DRAWINDEXEDINDIRECT:
870cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_DRAWINDEXEDINDIRECT";
871cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_DISPATCH:
872cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_DISPATCH";
873cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_DISPATCHINDIRECT:
874cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_DISPATCHINDIRECT";
875cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_COPYBUFFER:
876cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_COPYBUFFER";
877cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_COPYIMAGE:
878cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_COPYIMAGE";
879cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_BLITIMAGE:
880cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_BLITIMAGE";
881cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_COPYBUFFERTOIMAGE:
882cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_COPYBUFFERTOIMAGE";
883cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_COPYIMAGETOBUFFER:
884cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_COPYIMAGETOBUFFER";
885cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_CLONEIMAGEDATA:
886cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_CLONEIMAGEDATA";
887cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_UPDATEBUFFER:
888cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_UPDATEBUFFER";
889cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_FILLBUFFER:
890cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_FILLBUFFER";
891cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_CLEARCOLORIMAGE:
892cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_CLEARCOLORIMAGE";
893cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_CLEARATTACHMENTS:
894cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_CLEARCOLORATTACHMENT";
895cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_CLEARDEPTHSTENCILIMAGE:
896cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_CLEARDEPTHSTENCILIMAGE";
897cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_RESOLVEIMAGE:
898cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_RESOLVEIMAGE";
899cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SETEVENT:
900cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SETEVENT";
901cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_RESETEVENT:
902cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_RESETEVENT";
903cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_WAITEVENTS:
904cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_WAITEVENTS";
905cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_PIPELINEBARRIER:
906cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_PIPELINEBARRIER";
907cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_BEGINQUERY:
908cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_BEGINQUERY";
909cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_ENDQUERY:
910cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_ENDQUERY";
911cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_RESETQUERYPOOL:
912cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_RESETQUERYPOOL";
913cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_COPYQUERYPOOLRESULTS:
914cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_COPYQUERYPOOLRESULTS";
915cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_WRITETIMESTAMP:
916cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_WRITETIMESTAMP";
917cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_INITATOMICCOUNTERS:
918cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_INITATOMICCOUNTERS";
919cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_LOADATOMICCOUNTERS:
920cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_LOADATOMICCOUNTERS";
921cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_SAVEATOMICCOUNTERS:
922cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_SAVEATOMICCOUNTERS";
923cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_BEGINRENDERPASS:
924cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_BEGINRENDERPASS";
925cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case CMD_ENDRENDERPASS:
926cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "CMD_ENDRENDERPASS";
927cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
928cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "UNKNOWN";
9295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
9315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// SPIRV utility functions
9335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic void build_def_index(shader_module *module) {
9345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *module) {
9355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        switch (insn.opcode()) {
936cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Types
937cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeVoid:
938cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeBool:
939cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeInt:
940cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeFloat:
941cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeVector:
942cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeMatrix:
943cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeImage:
944cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeSampler:
945cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeSampledImage:
946cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeArray:
947cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeRuntimeArray:
948cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeStruct:
949cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeOpaque:
950cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypePointer:
951cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeFunction:
952cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeEvent:
953cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeDeviceEvent:
954cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeReserveId:
955cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeQueue:
956cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypePipe:
957cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                module->def_index[insn.word(1)] = insn.offset();
958cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
9595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
960cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Fixed constants
961cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstantTrue:
962cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstantFalse:
963cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstant:
964cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstantComposite:
965cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstantSampler:
966cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstantNull:
967cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                module->def_index[insn.word(2)] = insn.offset();
968cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
9695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
970cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Specialization constants
971cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpSpecConstantTrue:
972cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpSpecConstantFalse:
973cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpSpecConstant:
974cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpSpecConstantComposite:
975cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpSpecConstantOp:
976cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                module->def_index[insn.word(2)] = insn.offset();
977cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
9785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
979cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Variables
980cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpVariable:
981cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                module->def_index[insn.word(2)] = insn.offset();
982cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
9835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
984cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Functions
985cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpFunction:
986cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                module->def_index[insn.word(2)] = insn.offset();
987cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
9885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
989cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
990cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // We don't care about any other defs for now.
991cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
9925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
9935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
9955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic spirv_inst_iter find_entrypoint(shader_module *src, char const *name, VkShaderStageFlagBits stageBits) {
9975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
9985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpEntryPoint) {
9995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            auto entrypointName = (char const *)&insn.word(3);
10005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            auto entrypointStageBits = 1u << insn.word(1);
10015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!strcmp(entrypointName, name) && (entrypointStageBits & stageBits)) {
10035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return insn;
10045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
10055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
10065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return src->end();
10095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
10105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic char const *storage_class_name(unsigned sc) {
10125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (sc) {
1013cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassInput:
1014cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "input";
1015cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassOutput:
1016cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "output";
1017cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassUniformConstant:
1018cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "const uniform";
1019cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassUniform:
1020cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "uniform";
1021cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassWorkgroup:
1022cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "workgroup local";
1023cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassCrossWorkgroup:
1024cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "workgroup global";
1025cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassPrivate:
1026cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "private global";
1027cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassFunction:
1028cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "function";
1029cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassGeneric:
1030cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "generic";
1031cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassAtomicCounter:
1032cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "atomic counter";
1033cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassImage:
1034cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "image";
1035cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassPushConstant:
1036cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "push constant";
1037cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1038cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "unknown";
10395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
10415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
104225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// Get the value of an integral constant
10435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisunsigned get_constant_value(shader_module const *src, unsigned id) {
10445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto value = src->get_def(id);
10455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(value != src->end());
10465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (value.opcode() != spv::OpConstant) {
104825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // TODO: Either ensure that the specialization transform is already performed on a module we're
104925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        //       considering here, OR -- specialize on the fly now.
10505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return 1;
10515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return value.word(3);
10545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
10555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10569ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbesstatic void describe_type_inner(std::ostringstream &ss, shader_module const *src, unsigned type) {
10575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto insn = src->get_def(type);
10585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(insn != src->end());
10595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (insn.opcode()) {
1061cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeBool:
1062cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "bool";
1063cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1064cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeInt:
1065cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << (insn.word(3) ? 's' : 'u') << "int" << insn.word(2);
1066cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1067cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeFloat:
1068cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "float" << insn.word(2);
1069cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1070cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeVector:
1071cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "vec" << insn.word(3) << " of ";
1072cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            describe_type_inner(ss, src, insn.word(2));
1073cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1074cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeMatrix:
1075cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "mat" << insn.word(3) << " of ";
1076cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            describe_type_inner(ss, src, insn.word(2));
1077cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1078cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeArray:
1079cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "arr[" << get_constant_value(src, insn.word(3)) << "] of ";
1080cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            describe_type_inner(ss, src, insn.word(2));
1081cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1082cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypePointer:
1083cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "ptr to " << storage_class_name(insn.word(2)) << " ";
1084cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            describe_type_inner(ss, src, insn.word(3));
1085cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1086cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeStruct: {
1087cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "struct of (";
1088cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            for (unsigned i = 2; i < insn.len(); i++) {
1089cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                describe_type_inner(ss, src, insn.word(i));
1090cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (i == insn.len() - 1) {
1091cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    ss << ")";
1092cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                } else {
1093cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    ss << ", ";
1094cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
10959ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes            }
1096cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
10975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
1098cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeSampler:
1099cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "sampler";
1100cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1101cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeSampledImage:
1102cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "sampler+";
1103cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            describe_type_inner(ss, src, insn.word(2));
1104cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1105cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeImage:
1106cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "image(dim=" << insn.word(3) << ", sampled=" << insn.word(7) << ")";
1107cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
1108cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1109cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "oddtype";
1110cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
11115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
11125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
11135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11149ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbesstatic std::string describe_type(shader_module const *src, unsigned type) {
11159ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes    std::ostringstream ss;
11169ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes    describe_type_inner(ss, src, type);
11179ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes    return ss.str();
11189ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes}
11199ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes
1120bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool is_narrow_numeric_type(spirv_inst_iter type) {
1121cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (type.opcode() != spv::OpTypeInt && type.opcode() != spv::OpTypeFloat) return false;
112237576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes    return type.word(2) < 64;
112337576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes}
112437576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes
1125bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool types_match(shader_module const *a, shader_module const *b, unsigned a_type, unsigned b_type, bool a_arrayed,
1126bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        bool b_arrayed, bool relaxed) {
112725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Walk two type trees together, and complain about differences
11285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto a_insn = a->get_def(a_type);
11295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto b_insn = b->get_def(b_type);
11305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(a_insn != a->end());
11315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(b_insn != b->end());
11325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11337c755c8aca6857046df9516d8336416165969cb9Chris Forbes    if (a_arrayed && a_insn.opcode() == spv::OpTypeArray) {
113437576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes        return types_match(a, b, a_insn.word(2), b_type, false, b_arrayed, relaxed);
11357c755c8aca6857046df9516d8336416165969cb9Chris Forbes    }
11367c755c8aca6857046df9516d8336416165969cb9Chris Forbes
11375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (b_arrayed && b_insn.opcode() == spv::OpTypeArray) {
113825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // We probably just found the extra level of arrayness in b_type: compare the type inside it to a_type
113937576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes        return types_match(a, b, a_type, b_insn.word(2), a_arrayed, false, relaxed);
114037576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes    }
114137576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes
114237576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes    if (a_insn.opcode() == spv::OpTypeVector && relaxed && is_narrow_numeric_type(b_insn)) {
114337576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes        return types_match(a, b, a_insn.word(2), b_type, a_arrayed, b_arrayed, false);
11445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
11455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (a_insn.opcode() != b_insn.opcode()) {
11475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return false;
11485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
11495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11507c755c8aca6857046df9516d8336416165969cb9Chris Forbes    if (a_insn.opcode() == spv::OpTypePointer) {
115125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Match on pointee type. storage class is expected to differ
115237576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes        return types_match(a, b, a_insn.word(3), b_insn.word(3), a_arrayed, b_arrayed, relaxed);
11537c755c8aca6857046df9516d8336416165969cb9Chris Forbes    }
11547c755c8aca6857046df9516d8336416165969cb9Chris Forbes
11557c755c8aca6857046df9516d8336416165969cb9Chris Forbes    if (a_arrayed || b_arrayed) {
115625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // If we havent resolved array-of-verts by here, we're not going to.
11577c755c8aca6857046df9516d8336416165969cb9Chris Forbes        return false;
11587c755c8aca6857046df9516d8336416165969cb9Chris Forbes    }
11597c755c8aca6857046df9516d8336416165969cb9Chris Forbes
11605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (a_insn.opcode()) {
1161cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeBool:
1162cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return true;
1163cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeInt:
1164cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on width, signedness
1165cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return a_insn.word(2) == b_insn.word(2) && a_insn.word(3) == b_insn.word(3);
1166cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeFloat:
1167cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on width
1168cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return a_insn.word(2) == b_insn.word(2);
1169cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeVector:
1170cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on element type, count.
1171cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (!types_match(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false)) return false;
1172cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (relaxed && is_narrow_numeric_type(a->get_def(a_insn.word(2)))) {
1173cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return a_insn.word(3) >= b_insn.word(3);
1174cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else {
1175cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return a_insn.word(3) == b_insn.word(3);
11765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
1177cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeMatrix:
1178cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on element type, count.
1179cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return types_match(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false) &&
1180cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                   a_insn.word(3) == b_insn.word(3);
1181cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeArray:
1182cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on element type, count. these all have the same layout. we don't get here if b_arrayed. This differs from
1183cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // vector & matrix types in that the array size is the id of a constant instruction, * not a literal within OpTypeArray
1184cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return types_match(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false) &&
1185cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                   get_constant_value(a, a_insn.word(3)) == get_constant_value(b, b_insn.word(3));
1186cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeStruct:
1187cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on all element types
1188cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            {
1189cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (a_insn.len() != b_insn.len()) {
1190cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    return false;  // Structs cannot match if member counts differ
1191cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
11925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1193cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                for (unsigned i = 2; i < a_insn.len(); i++) {
1194cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    if (!types_match(a, b, a_insn.word(i), b_insn.word(i), a_arrayed, b_arrayed, false)) {
1195cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return false;
1196cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    }
1197cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
1198cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski
1199cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return true;
1200cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
1201cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1202cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Remaining types are CLisms, or may not appear in the interfaces we are interested in. Just claim no match.
1203cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return false;
12045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
12055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
12065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic int value_or_default(std::unordered_map<unsigned, unsigned> const &map, unsigned id, int def) {
12085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto it = map.find(id);
12095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (it == map.end())
12105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return def;
12115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    else
12125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return it->second;
12135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
12145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic unsigned get_locations_consumed_by_type(shader_module const *src, unsigned type, bool strip_array_level) {
12165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto insn = src->get_def(type);
12175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(insn != src->end());
12185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (insn.opcode()) {
1220cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypePointer:
1221cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // See through the ptr -- this is only ever at the toplevel for graphics shaders we're never actually passing
1222cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // pointers around.
1223cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_locations_consumed_by_type(src, insn.word(3), strip_array_level);
1224cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeArray:
1225cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (strip_array_level) {
1226cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return get_locations_consumed_by_type(src, insn.word(2), false);
1227cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else {
1228cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return get_constant_value(src, insn.word(3)) * get_locations_consumed_by_type(src, insn.word(2), false);
1229cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
1230cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeMatrix:
1231cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Num locations is the dimension * element size
1232cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return insn.word(3) * get_locations_consumed_by_type(src, insn.word(2), false);
1233cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeVector: {
1234cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            auto scalar_type = src->get_def(insn.word(2));
1235cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            auto bit_width =
1236cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                (scalar_type.opcode() == spv::OpTypeInt || scalar_type.opcode() == spv::OpTypeFloat) ? scalar_type.word(2) : 32;
1237cc52143fc093e1e62d2dacc4abc3966e04b6f6d6Chris Forbes
1238cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Locations are 128-bit wide; 3- and 4-component vectors of 64 bit types require two.
1239cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return (bit_width * insn.word(3) + 127) / 128;
1240cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
1241cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1242cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Everything else is just 1.
1243cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return 1;
12445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1245cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // TODO: extend to handle 64bit scalar types, whose vectors may need multiple locations.
12465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
12475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
12485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1249c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbesstatic unsigned get_locations_consumed_by_format(VkFormat format) {
1250c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes    switch (format) {
1251cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64A64_SFLOAT:
1252cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64A64_SINT:
1253cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64A64_UINT:
1254cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64_SFLOAT:
1255cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64_SINT:
1256cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64_UINT:
1257cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return 2;
1258cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1259cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return 1;
1260c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes    }
1261c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes}
1262c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes
12635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlistypedef std::pair<unsigned, unsigned> location_t;
12645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlistypedef std::pair<unsigned, unsigned> descriptor_slot_t;
12655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstruct interface_var {
12675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t id;
12685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t type_id;
12695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t offset;
1270b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes    bool is_patch;
1271fff9393206f66a154438e16fa0562c989f425498Chris Forbes    bool is_block_member;
1272b0436668e6594b8528e96de7bed208399fb2431dChris Forbes    bool is_relaxed_precision;
127325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // TODO: collect the name, too? Isn't required to be present.
12745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis};
12755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1276031261d21af8907953dd763398ce9a23e65b8749Chris Forbesstruct shader_stage_attributes {
1277031261d21af8907953dd763398ce9a23e65b8749Chris Forbes    char const *const name;
1278031261d21af8907953dd763398ce9a23e65b8749Chris Forbes    bool arrayed_input;
1279031261d21af8907953dd763398ce9a23e65b8749Chris Forbes    bool arrayed_output;
1280031261d21af8907953dd763398ce9a23e65b8749Chris Forbes};
1281031261d21af8907953dd763398ce9a23e65b8749Chris Forbes
1282031261d21af8907953dd763398ce9a23e65b8749Chris Forbesstatic shader_stage_attributes shader_stage_attribs[] = {
1283bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    {"vertex shader", false, false},  {"tessellation control shader", true, true}, {"tessellation evaluation shader", true, false},
1284bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    {"geometry shader", true, false}, {"fragment shader", false, false},
1285031261d21af8907953dd763398ce9a23e65b8749Chris Forbes};
1286031261d21af8907953dd763398ce9a23e65b8749Chris Forbes
12875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic spirv_inst_iter get_struct_type(shader_module const *src, spirv_inst_iter def, bool is_array_of_verts) {
12885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while (true) {
12895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (def.opcode() == spv::OpTypePointer) {
12905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            def = src->get_def(def.word(3));
12915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (def.opcode() == spv::OpTypeArray && is_array_of_verts) {
12925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            def = src->get_def(def.word(2));
12935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            is_array_of_verts = false;
12945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (def.opcode() == spv::OpTypeStruct) {
12955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return def;
12965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
12975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return src->end();
12985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
12995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
13005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
13015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1302bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic void collect_interface_block_members(shader_module const *src, std::map<location_t, interface_var> *out,
13035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                            std::unordered_map<unsigned, unsigned> const &blocks, bool is_array_of_verts,
1304b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes                                            uint32_t id, uint32_t type_id, bool is_patch) {
130525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Walk down the type_id presented, trying to determine whether it's actually an interface block.
1306031261d21af8907953dd763398ce9a23e65b8749Chris Forbes    auto type = get_struct_type(src, src->get_def(type_id), is_array_of_verts && !is_patch);
13075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (type == src->end() || blocks.find(type.word(1)) == blocks.end()) {
130825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // This isn't an interface block.
13095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return;
13105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
13115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> member_components;
13135b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes    std::unordered_map<unsigned, unsigned> member_relaxed_precision;
13145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
131525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Walk all the OpMemberDecorate for type's result id -- first pass, collect components.
13165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
13175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
13185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned member_index = insn.word(2);
13195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(3) == spv::DecorationComponent) {
13215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                unsigned component = insn.word(4);
13225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                member_components[member_index] = component;
13235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
13245b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes
13255b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes            if (insn.word(3) == spv::DecorationRelaxedPrecision) {
13265b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes                member_relaxed_precision[member_index] = 1;
13275b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes            }
13285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
13295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
13305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
133125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Second pass -- produce the output, from Location decorations
13325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
13335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
13345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned member_index = insn.word(2);
13355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned member_type_id = type.word(2 + member_index);
13365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(3) == spv::DecorationLocation) {
13385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                unsigned location = insn.word(4);
13395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                unsigned num_locations = get_locations_consumed_by_type(src, member_type_id, false);
13405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                auto component_it = member_components.find(member_index);
13415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                unsigned component = component_it == member_components.end() ? 0 : component_it->second;
13425b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes                bool is_relaxed_precision = member_relaxed_precision.find(member_index) != member_relaxed_precision.end();
13435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                for (unsigned int offset = 0; offset < num_locations; offset++) {
1345b0436668e6594b8528e96de7bed208399fb2431dChris Forbes                    interface_var v = {};
13465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.id = id;
134725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski                    // TODO: member index in interface_var too?
13485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.type_id = member_type_id;
13495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.offset = offset;
1350b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes                    v.is_patch = is_patch;
1351fff9393206f66a154438e16fa0562c989f425498Chris Forbes                    v.is_block_member = true;
13525b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes                    v.is_relaxed_precision = is_relaxed_precision;
13533a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes                    (*out)[std::make_pair(location + offset, component)] = v;
13545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
13555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
13565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
13575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
13585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
13595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1360bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic std::map<location_t, interface_var> collect_interface_by_location(shader_module const *src, spirv_inst_iter entrypoint,
1361bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                         spv::StorageClass sinterface, bool is_array_of_verts) {
13625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> var_locations;
13635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> var_builtins;
13645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> var_components;
13655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> blocks;
1366b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes    std::unordered_map<unsigned, unsigned> var_patch;
1367b0436668e6594b8528e96de7bed208399fb2431dChris Forbes    std::unordered_map<unsigned, unsigned> var_relaxed_precision;
13685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
137025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // We consider two interface models: SSO rendezvous-by-location, and builtins. Complain about anything that
137125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // fits neither model.
13725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpDecorate) {
13735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationLocation) {
13745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                var_locations[insn.word(1)] = insn.word(3);
13755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
13765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationBuiltIn) {
13785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                var_builtins[insn.word(1)] = insn.word(3);
13795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
13805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationComponent) {
13825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                var_components[insn.word(1)] = insn.word(3);
13835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
13845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationBlock) {
13865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                blocks[insn.word(1)] = 1;
13875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
1388b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes
1389b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes            if (insn.word(2) == spv::DecorationPatch) {
1390b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes                var_patch[insn.word(1)] = 1;
1391b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes            }
1392b0436668e6594b8528e96de7bed208399fb2431dChris Forbes
1393b0436668e6594b8528e96de7bed208399fb2431dChris Forbes            if (insn.word(2) == spv::DecorationRelaxedPrecision) {
1394b0436668e6594b8528e96de7bed208399fb2431dChris Forbes                var_relaxed_precision[insn.word(1)] = 1;
1395b0436668e6594b8528e96de7bed208399fb2431dChris Forbes            }
13965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
13975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
13985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
139925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // TODO: handle grouped decorations
140025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // TODO: handle index=1 dual source outputs from FS -- two vars will have the same location, and we DON'T want to clobber.
14015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
140225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Find the end of the entrypoint's name string. additional zero bytes follow the actual null terminator, to fill out the
140325002b75574f762c62b1a00a595bab04ebb25452Mark 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.
1404c15b801a6e1a5dd5eed09e689aecdde7c4a90a5bMichael Mc Donnell    uint32_t word = 3;
14055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while (entrypoint.word(word) & 0xff000000u) {
14065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        ++word;
14075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
14085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    ++word;
14095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14103a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    std::map<location_t, interface_var> out;
14113a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
14125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (; word < entrypoint.len(); word++) {
14135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto insn = src->get_def(entrypoint.word(word));
14145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        assert(insn != src->end());
14155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        assert(insn.opcode() == spv::OpVariable);
14165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14171d5109d5e0dcc530b27e632e73e1be5e12a28dcdJamie Madill        if (insn.word(3) == static_cast<uint32_t>(sinterface)) {
14185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned id = insn.word(2);
14195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned type = insn.word(1);
14205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            int location = value_or_default(var_locations, id, -1);
14225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            int builtin = value_or_default(var_builtins, id, -1);
1423cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            unsigned component = value_or_default(var_components, id, 0);  // Unspecified is OK, is 0
1424b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes            bool is_patch = var_patch.find(id) != var_patch.end();
1425b0436668e6594b8528e96de7bed208399fb2431dChris Forbes            bool is_relaxed_precision = var_relaxed_precision.find(id) != var_relaxed_precision.end();
14265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
142725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // All variables and interface block members in the Input or Output storage classes must be decorated with either
142825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // a builtin or an explicit location.
142925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            //
143025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // TODO: integrate the interface block support here. For now, don't complain -- a valid SPIRV module will only hit
143125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // this path for the interface block case, as the individual members of the type are decorated, rather than
143225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // variable declarations.
14335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (location != -1) {
143525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski                // A user-defined interface variable, with a location. Where a variable occupied multiple locations, emit
143625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski                // one result for each.
14377c755c8aca6857046df9516d8336416165969cb9Chris Forbes                unsigned num_locations = get_locations_consumed_by_type(src, type, is_array_of_verts && !is_patch);
14385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                for (unsigned int offset = 0; offset < num_locations; offset++) {
1439b0436668e6594b8528e96de7bed208399fb2431dChris Forbes                    interface_var v = {};
14405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.id = id;
14415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.type_id = type;
14425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.offset = offset;
1443b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes                    v.is_patch = is_patch;
1444b0436668e6594b8528e96de7bed208399fb2431dChris Forbes                    v.is_relaxed_precision = is_relaxed_precision;
14455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    out[std::make_pair(location + offset, component)] = v;
14465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
14475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else if (builtin == -1) {
144825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski                // An interface block instance
14493a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes                collect_interface_block_members(src, &out, blocks, is_array_of_verts, id, type, is_patch);
14505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
14515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
14525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
14533a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
14543a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    return out;
14555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
14565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1457cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskistatic std::vector<std::pair<uint32_t, interface_var>> collect_interface_by_input_attachment_index(
1458cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    debug_report_data *report_data, shader_module const *src, std::unordered_set<uint32_t> const &accessible_ids) {
14593a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    std::vector<std::pair<uint32_t, interface_var>> out;
1460745d49409296f060402b57950384caadb636a2b2Chris Forbes
1461745d49409296f060402b57950384caadb636a2b2Chris Forbes    for (auto insn : *src) {
1462745d49409296f060402b57950384caadb636a2b2Chris Forbes        if (insn.opcode() == spv::OpDecorate) {
1463745d49409296f060402b57950384caadb636a2b2Chris Forbes            if (insn.word(2) == spv::DecorationInputAttachmentIndex) {
1464745d49409296f060402b57950384caadb636a2b2Chris Forbes                auto attachment_index = insn.word(3);
1465745d49409296f060402b57950384caadb636a2b2Chris Forbes                auto id = insn.word(1);
1466745d49409296f060402b57950384caadb636a2b2Chris Forbes
1467745d49409296f060402b57950384caadb636a2b2Chris Forbes                if (accessible_ids.count(id)) {
1468745d49409296f060402b57950384caadb636a2b2Chris Forbes                    auto def = src->get_def(id);
1469745d49409296f060402b57950384caadb636a2b2Chris Forbes                    assert(def != src->end());
1470745d49409296f060402b57950384caadb636a2b2Chris Forbes
1471745d49409296f060402b57950384caadb636a2b2Chris Forbes                    if (def.opcode() == spv::OpVariable && insn.word(3) == spv::StorageClassUniformConstant) {
1472e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                        auto num_locations = get_locations_consumed_by_type(src, def.word(1), false);
1473e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                        for (unsigned int offset = 0; offset < num_locations; offset++) {
1474b0436668e6594b8528e96de7bed208399fb2431dChris Forbes                            interface_var v = {};
1475e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                            v.id = id;
1476e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                            v.type_id = def.word(1);
1477e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                            v.offset = offset;
1478e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                            out.emplace_back(attachment_index + offset, v);
1479e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                        }
1480745d49409296f060402b57950384caadb636a2b2Chris Forbes                    }
1481745d49409296f060402b57950384caadb636a2b2Chris Forbes                }
1482745d49409296f060402b57950384caadb636a2b2Chris Forbes            }
1483745d49409296f060402b57950384caadb636a2b2Chris Forbes        }
1484745d49409296f060402b57950384caadb636a2b2Chris Forbes    }
14853a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
14863a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    return out;
1487745d49409296f060402b57950384caadb636a2b2Chris Forbes}
1488745d49409296f060402b57950384caadb636a2b2Chris Forbes
1489cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskistatic std::vector<std::pair<descriptor_slot_t, interface_var>> collect_interface_by_descriptor_slot(
1490cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    debug_report_data *report_data, shader_module const *src, std::unordered_set<uint32_t> const &accessible_ids) {
14915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> var_sets;
14925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> var_bindings;
14935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
149525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // All variables in the Uniform or UniformConstant storage classes are required to be decorated with both
149625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // DecorationDescriptorSet and DecorationBinding.
14975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpDecorate) {
14985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationDescriptorSet) {
14995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                var_sets[insn.word(1)] = insn.word(3);
15005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
15015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationBinding) {
15035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                var_bindings[insn.word(1)] = insn.word(3);
15045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
15055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
15065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
15075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15083a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    std::vector<std::pair<descriptor_slot_t, interface_var>> out;
15093a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
15105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto id : accessible_ids) {
15115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto insn = src->get_def(id);
15125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        assert(insn != src->end());
15135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpVariable &&
15155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            (insn.word(3) == spv::StorageClassUniform || insn.word(3) == spv::StorageClassUniformConstant)) {
15165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned set = value_or_default(var_sets, insn.word(2), 0);
15175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned binding = value_or_default(var_bindings, insn.word(2), 0);
15185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1519b0436668e6594b8528e96de7bed208399fb2431dChris Forbes            interface_var v = {};
15205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            v.id = insn.word(2);
15215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            v.type_id = insn.word(1);
1522cefd4dd8e03c5dae11a05d04a03cb856190358e0Chris Forbes            out.emplace_back(std::make_pair(set, binding), v);
15235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
15245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
15253a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
15263a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    return out;
15275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
15285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1529edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_interface_between_stages(debug_report_data *report_data, shader_module const *producer,
1530031261d21af8907953dd763398ce9a23e65b8749Chris Forbes                                              spirv_inst_iter producer_entrypoint, shader_stage_attributes const *producer_stage,
15315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                              shader_module const *consumer, spirv_inst_iter consumer_entrypoint,
1532031261d21af8907953dd763398ce9a23e65b8749Chris Forbes                                              shader_stage_attributes const *consumer_stage) {
15335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool pass = true;
15345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1535bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto outputs =
1536bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        collect_interface_by_location(producer, producer_entrypoint, spv::StorageClassOutput, producer_stage->arrayed_output);
1537bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto inputs =
1538bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        collect_interface_by_location(consumer, consumer_entrypoint, spv::StorageClassInput, consumer_stage->arrayed_input);
15395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto a_it = outputs.begin();
15415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto b_it = inputs.begin();
15425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
154325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Maps sorted by key (location); walk them together to find mismatches
15445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while ((outputs.size() > 0 && a_it != outputs.end()) || (inputs.size() && b_it != inputs.end())) {
15455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        bool a_at_end = outputs.size() == 0 || a_it == outputs.end();
15465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        bool b_at_end = inputs.size() == 0 || b_it == inputs.end();
15475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto a_first = a_at_end ? std::make_pair(0u, 0u) : a_it->first;
15485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto b_first = b_at_end ? std::make_pair(0u, 0u) : b_it->first;
15495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (b_at_end || ((!a_at_end) && (a_first < b_first))) {
1551bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
1552bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC", "%s writes to output location %u.%u which is not consumed by %s",
1553bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        producer_stage->name, a_first.first, a_first.second, consumer_stage->name)) {
15545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pass = false;
15555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
15565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            a_it++;
15575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (a_at_end || a_first > b_first) {
1558bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
1559bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "%s consumes input location %u.%u which is not written by %s",
1560bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        consumer_stage->name, b_first.first, b_first.second, producer_stage->name)) {
15615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pass = false;
15625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
15635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            b_it++;
15645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
1565fff9393206f66a154438e16fa0562c989f425498Chris Forbes            // subtleties of arrayed interfaces:
1566fff9393206f66a154438e16fa0562c989f425498Chris Forbes            // - if is_patch, then the member is not arrayed, even though the interface may be.
1567fff9393206f66a154438e16fa0562c989f425498Chris Forbes            // - if is_block_member, then the extra array level of an arrayed interface is not
1568fff9393206f66a154438e16fa0562c989f425498Chris Forbes            //   expressed in the member type -- it's expressed in the block type.
15690f44c68c2575ba2fc83d8c8f2f5ea09548f40686Chris Forbes            if (!types_match(producer, consumer, a_it->second.type_id, b_it->second.type_id,
1570fff9393206f66a154438e16fa0562c989f425498Chris Forbes                             producer_stage->arrayed_output && !a_it->second.is_patch && !a_it->second.is_block_member,
1571bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             consumer_stage->arrayed_input && !b_it->second.is_patch && !b_it->second.is_block_member, true)) {
1572bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
1573bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC", "Type mismatch on location %u.%u: '%s' vs '%s'",
1574bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            a_first.first, a_first.second, describe_type(producer, a_it->second.type_id).c_str(),
15759ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes                            describe_type(consumer, b_it->second.type_id).c_str())) {
15765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    pass = false;
15775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
15785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
15790f44c68c2575ba2fc83d8c8f2f5ea09548f40686Chris Forbes            if (a_it->second.is_patch != b_it->second.is_patch) {
1580bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
1581bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
1582f706c50be3a9d4d1e131c2f43ee2fb443f028d30Chris Forbes                            "Decoration mismatch on location %u.%u: is per-%s in %s stage but "
1583bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "per-%s in %s stage",
1584bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            a_first.first, a_first.second, a_it->second.is_patch ? "patch" : "vertex", producer_stage->name,
15850f44c68c2575ba2fc83d8c8f2f5ea09548f40686Chris Forbes                            b_it->second.is_patch ? "patch" : "vertex", consumer_stage->name)) {
15860f44c68c2575ba2fc83d8c8f2f5ea09548f40686Chris Forbes                    pass = false;
15870f44c68c2575ba2fc83d8c8f2f5ea09548f40686Chris Forbes                }
15880f44c68c2575ba2fc83d8c8f2f5ea09548f40686Chris Forbes            }
158917c6bacf91ac671cb33212071b87b8ea782812f5Chris Forbes            if (a_it->second.is_relaxed_precision != b_it->second.is_relaxed_precision) {
1590bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
1591bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
1592bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "Decoration mismatch on location %u.%u: %s and %s stages differ in precision", a_first.first,
1593bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            a_first.second, producer_stage->name, consumer_stage->name)) {
159417c6bacf91ac671cb33212071b87b8ea782812f5Chris Forbes                    pass = false;
159517c6bacf91ac671cb33212071b87b8ea782812f5Chris Forbes                }
159617c6bacf91ac671cb33212071b87b8ea782812f5Chris Forbes            }
15975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            a_it++;
15985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            b_it++;
15995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
16005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
16015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
16025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return pass;
16035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
16045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
16055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisenum FORMAT_TYPE {
1606f0fdde7692ffd5175435cc3bf3412b8468054f38Chris Forbes    FORMAT_TYPE_FLOAT = 1,  // UNORM, SNORM, FLOAT, USCALED, SSCALED, SRGB -- anything we consider float in the shader
1607f0fdde7692ffd5175435cc3bf3412b8468054f38Chris Forbes    FORMAT_TYPE_SINT = 2,
1608f0fdde7692ffd5175435cc3bf3412b8468054f38Chris Forbes    FORMAT_TYPE_UINT = 4,
16095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis};
16105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
16115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic unsigned get_format_type(VkFormat fmt) {
16125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (fmt) {
1613cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_UNDEFINED:
1614f0fdde7692ffd5175435cc3bf3412b8468054f38Chris Forbes            return 0;
1615cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R8_SINT:
1616cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R8G8_SINT:
1617cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R8G8B8_SINT:
1618cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R8G8B8A8_SINT:
1619cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R16_SINT:
1620cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R16G16_SINT:
1621cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R16G16B16_SINT:
1622cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R16G16B16A16_SINT:
1623cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R32_SINT:
1624cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R32G32_SINT:
1625cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R32G32B32_SINT:
1626cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R32G32B32A32_SINT:
1627cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64_SINT:
1628cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64_SINT:
1629cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64_SINT:
1630cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64A64_SINT:
1631cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_B8G8R8_SINT:
1632cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_B8G8R8A8_SINT:
1633cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_A8B8G8R8_SINT_PACK32:
1634cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_A2B10G10R10_SINT_PACK32:
1635cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_A2R10G10B10_SINT_PACK32:
1636cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return FORMAT_TYPE_SINT;
1637cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R8_UINT:
1638cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R8G8_UINT:
1639cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R8G8B8_UINT:
1640cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R8G8B8A8_UINT:
1641cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R16_UINT:
1642cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R16G16_UINT:
1643cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R16G16B16_UINT:
1644cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R16G16B16A16_UINT:
1645cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R32_UINT:
1646cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R32G32_UINT:
1647cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R32G32B32_UINT:
1648cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R32G32B32A32_UINT:
1649cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64_UINT:
1650cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64_UINT:
1651cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64_UINT:
1652cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64A64_UINT:
1653cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_B8G8R8_UINT:
1654cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_B8G8R8A8_UINT:
1655cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_A8B8G8R8_UINT_PACK32:
1656cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_A2B10G10R10_UINT_PACK32:
1657cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_A2R10G10B10_UINT_PACK32:
1658cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return FORMAT_TYPE_UINT;
1659c3e75516f42455703d7577ecf7fb5aceb876e1f7Chris Forbes        case VK_FORMAT_D16_UNORM_S8_UINT:
1660c3e75516f42455703d7577ecf7fb5aceb876e1f7Chris Forbes        case VK_FORMAT_D24_UNORM_S8_UINT:
1661c3e75516f42455703d7577ecf7fb5aceb876e1f7Chris Forbes        case VK_FORMAT_D32_SFLOAT_S8_UINT:
1662c3e75516f42455703d7577ecf7fb5aceb876e1f7Chris Forbes            return FORMAT_TYPE_FLOAT | FORMAT_TYPE_UINT;
1663cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1664cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return FORMAT_TYPE_FLOAT;
16655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
16665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
16675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
166825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// characterizes a SPIR-V type appearing in an interface to a FF stage, for comparison to a VkFormat's characterization above.
16695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic unsigned get_fundamental_type(shader_module const *src, unsigned type) {
16705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto insn = src->get_def(type);
16715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(insn != src->end());
16725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
16735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (insn.opcode()) {
1674cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeInt:
1675cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return insn.word(3) ? FORMAT_TYPE_SINT : FORMAT_TYPE_UINT;
1676cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeFloat:
1677cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return FORMAT_TYPE_FLOAT;
1678cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeVector:
1679cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_fundamental_type(src, insn.word(2));
1680cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeMatrix:
1681cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_fundamental_type(src, insn.word(2));
1682cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeArray:
1683cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_fundamental_type(src, insn.word(2));
1684cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypePointer:
1685cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_fundamental_type(src, insn.word(3));
1686cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeImage:
1687cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_fundamental_type(src, insn.word(2));
1688cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski
1689cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1690f0fdde7692ffd5175435cc3bf3412b8468054f38Chris Forbes            return 0;
16915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
16925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
16935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
16945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic uint32_t get_shader_stage_id(VkShaderStageFlagBits stage) {
16955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t bit_pos = u_ffs(stage);
16965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return bit_pos - 1;
16975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
16985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1699edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_vi_consistency(debug_report_data *report_data, VkPipelineVertexInputStateCreateInfo const *vi) {
170025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Walk the binding descriptions, which describe the step rate and stride of each vertex buffer.  Each binding should
170125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // be specified only once.
17025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<uint32_t, VkVertexInputBindingDescription const *> bindings;
17035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool pass = true;
17045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (unsigned i = 0; i < vi->vertexBindingDescriptionCount; i++) {
17065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto desc = &vi->pVertexBindingDescriptions[i];
17075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto &binding = bindings[desc->binding];
17085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (binding) {
17094f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes            // TODO: VALIDATION_ERROR_02105 perhaps?
1710bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
1711bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        SHADER_CHECKER_INCONSISTENT_VI, "SC", "Duplicate vertex input binding descriptions for binding %d",
1712bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        desc->binding)) {
17135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pass = false;
17145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
17155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
17165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            binding = desc;
17175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
17185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
17195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return pass;
17215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
17225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1723edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_vi_against_vs_inputs(debug_report_data *report_data, VkPipelineVertexInputStateCreateInfo const *vi,
17245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                          shader_module const *vs, spirv_inst_iter entrypoint) {
17255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool pass = true;
17265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17273a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    auto inputs = collect_interface_by_location(vs, entrypoint, spv::StorageClassInput, false);
17285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
172925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Build index by location
17305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::map<uint32_t, VkVertexInputAttributeDescription const *> attribs;
17315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (vi) {
1732c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes        for (unsigned i = 0; i < vi->vertexAttributeDescriptionCount; i++) {
1733c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes            auto num_locations = get_locations_consumed_by_format(vi->pVertexAttributeDescriptions[i].format);
1734c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes            for (auto j = 0u; j < num_locations; j++) {
1735c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes                attribs[vi->pVertexAttributeDescriptions[i].location + j] = &vi->pVertexAttributeDescriptions[i];
1736c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes            }
1737c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes        }
17385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
17395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto it_a = attribs.begin();
17415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto it_b = inputs.begin();
17421730e0dd28b3abc660b4e4704cf6d414f7fd4ad6Chris Forbes    bool used = false;
17435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while ((attribs.size() > 0 && it_a != attribs.end()) || (inputs.size() > 0 && it_b != inputs.end())) {
17455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        bool a_at_end = attribs.size() == 0 || it_a == attribs.end();
17465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        bool b_at_end = inputs.size() == 0 || it_b == inputs.end();
17475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto a_first = a_at_end ? 0 : it_a->first;
17485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto b_first = b_at_end ? 0 : it_b->first.first;
17495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!a_at_end && (b_at_end || a_first < b_first)) {
17501730e0dd28b3abc660b4e4704cf6d414f7fd4ad6Chris Forbes            if (!used && log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
1751bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 __LINE__, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",
1752bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 "Vertex attribute at location %d not consumed by vertex shader", a_first)) {
17535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pass = false;
17545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
17551730e0dd28b3abc660b4e4704cf6d414f7fd4ad6Chris Forbes            used = false;
17565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            it_a++;
17575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (!b_at_end && (a_at_end || b_first < a_first)) {
1758bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
1759bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "Vertex shader consumes input at location %d but not provided",
17605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        b_first)) {
17615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pass = false;
17625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
17635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            it_b++;
17645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
17655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned attrib_type = get_format_type(it_a->second->format);
17665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned input_type = get_fundamental_type(vs, it_b->second.type_id);
17675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
176825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // Type checking
1769f0fdde7692ffd5175435cc3bf3412b8468054f38Chris Forbes            if (!(attrib_type & input_type)) {
1770bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
1771bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
17724b5890faffa54a735782a6b0a628a991ddc86944Mike Weiblen                            "Attribute type of `%s` at location %d does not match vertex shader input type of `%s`",
1773bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            string_VkFormat(it_a->second->format), a_first, describe_type(vs, it_b->second.type_id).c_str())) {
17745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    pass = false;
17755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
17765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
17775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
177825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // OK!
17791730e0dd28b3abc660b4e4704cf6d414f7fd4ad6Chris Forbes            used = true;
17805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            it_b++;
17815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
17825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
17835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return pass;
17855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
17865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1787edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_fs_outputs_against_render_pass(debug_report_data *report_data, shader_module const *fs,
17888da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis                                                    spirv_inst_iter entrypoint, VkRenderPassCreateInfo const *rpci,
17898da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis                                                    uint32_t subpass_index) {
1790025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes    std::map<uint32_t, VkFormat> color_attachments;
17918da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis    auto subpass = rpci->pSubpasses[subpass_index];
17928da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis    for (auto i = 0u; i < subpass.colorAttachmentCount; ++i) {
1793d9da90d92748c37962766868f8b0354637672c2aTobin Ehlis        uint32_t attachment = subpass.pColorAttachments[i].attachment;
1794cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (attachment == VK_ATTACHMENT_UNUSED) continue;
1795d9da90d92748c37962766868f8b0354637672c2aTobin Ehlis        if (rpci->pAttachments[attachment].format != VK_FORMAT_UNDEFINED) {
1796d9da90d92748c37962766868f8b0354637672c2aTobin Ehlis            color_attachments[i] = rpci->pAttachments[attachment].format;
1797025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes        }
1798025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes    }
1799025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes
18005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool pass = true;
18015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
180225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // TODO: dual source blend index (spv::DecIndex, zero if not provided)
18035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18043a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    auto outputs = collect_interface_by_location(fs, entrypoint, spv::StorageClassOutput, false);
18055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1806025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes    auto it_a = outputs.begin();
1807025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes    auto it_b = color_attachments.begin();
18085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
180925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Walk attachment list and outputs together
1810025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes
1811025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes    while ((outputs.size() > 0 && it_a != outputs.end()) || (color_attachments.size() > 0 && it_b != color_attachments.end())) {
1812025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes        bool a_at_end = outputs.size() == 0 || it_a == outputs.end();
1813025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes        bool b_at_end = color_attachments.size() == 0 || it_b == color_attachments.end();
18145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1815025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes        if (!a_at_end && (b_at_end || it_a->first.first < it_b->first)) {
1816bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
1817bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",
1818d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen                        "fragment shader writes to output location %d with no matching attachment", it_a->first.first)) {
18195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pass = false;
18205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
1821025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            it_a++;
1822025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes        } else if (!b_at_end && (a_at_end || it_a->first.first > it_b->first)) {
1823bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
1824bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "Attachment %d not written by fragment shader", it_b->first)) {
18255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pass = false;
18265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
1827025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            it_b++;
18285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
1829025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            unsigned output_type = get_fundamental_type(fs, it_a->second.type_id);
1830025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            unsigned att_type = get_format_type(it_b->second);
18315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
183225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // Type checking
1833f0fdde7692ffd5175435cc3bf3412b8468054f38Chris Forbes            if (!(output_type & att_type)) {
1834bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
1835bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
1836d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen                            "Attachment %d of type `%s` does not match fragment shader output type of `%s`", it_b->first,
1837bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            string_VkFormat(it_b->second), describe_type(fs, it_a->second.type_id).c_str())) {
18385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    pass = false;
18395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
18405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
18415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
184225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // OK!
1843025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            it_a++;
1844025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            it_b++;
18455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
18465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
18475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return pass;
18495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
18505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
185125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// For some analyses, we need to know about all ids referenced by the static call tree of a particular entrypoint. This is
185225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// important for identifying the set of shader resources actually used by an entrypoint, for example.
185325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// Note: we only explore parts of the image which might actually contain ids we care about for the above analyses.
185425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski//  - NOT the shader input/output interfaces.
185525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski//
185625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// TODO: The set of interesting opcodes here was determined by eyeballing the SPIRV spec. It might be worth
185725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// converting parts of this to be generated from the machine-readable spec instead.
18583a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbesstatic std::unordered_set<uint32_t> mark_accessible_ids(shader_module const *src, spirv_inst_iter entrypoint) {
18593a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    std::unordered_set<uint32_t> ids;
18605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_set<uint32_t> worklist;
18615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    worklist.insert(entrypoint.word(2));
18625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while (!worklist.empty()) {
18645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto id_iter = worklist.begin();
18655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto id = *id_iter;
18665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        worklist.erase(id_iter);
18675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto insn = src->get_def(id);
18695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn == src->end()) {
187025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // ID is something we didn't collect in build_def_index. that's OK -- we'll stumble across all kinds of things here
187125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // that we may not care about.
18725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            continue;
18735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
18745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
187525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Try to add to the output set
18765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!ids.insert(id).second) {
1877cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            continue;  // If we already saw this id, we don't want to walk it again.
18785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
18795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        switch (insn.opcode()) {
1881cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpFunction:
1882cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // Scan whole body of the function, enlisting anything interesting
1883cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                while (++insn, insn.opcode() != spv::OpFunctionEnd) {
1884cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    switch (insn.opcode()) {
1885cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpLoad:
1886cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicLoad:
1887cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicExchange:
1888cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicCompareExchange:
1889cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicCompareExchangeWeak:
1890cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicIIncrement:
1891cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicIDecrement:
1892cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicIAdd:
1893cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicISub:
1894cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicSMin:
1895cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicUMin:
1896cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicSMax:
1897cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicUMax:
1898cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicAnd:
1899cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicOr:
1900cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicXor:
1901cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            worklist.insert(insn.word(3));  // ptr
1902cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
1903cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpStore:
1904cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicStore:
1905cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            worklist.insert(insn.word(1));  // ptr
1906cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
1907cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAccessChain:
1908cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpInBoundsAccessChain:
1909cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            worklist.insert(insn.word(3));  // base ptr
1910cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
1911cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpSampledImage:
1912cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleImplicitLod:
1913cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleExplicitLod:
1914cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleDrefImplicitLod:
1915cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleDrefExplicitLod:
1916cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleProjImplicitLod:
1917cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleProjExplicitLod:
1918cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleProjDrefImplicitLod:
1919cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleProjDrefExplicitLod:
1920cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageFetch:
1921cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageGather:
1922cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageDrefGather:
1923cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageRead:
1924cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImage:
1925cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQueryFormat:
1926cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQueryOrder:
1927cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQuerySizeLod:
1928cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQuerySize:
1929cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQueryLod:
1930cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQueryLevels:
1931cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQuerySamples:
1932cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleImplicitLod:
1933cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleExplicitLod:
1934cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleDrefImplicitLod:
1935cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleDrefExplicitLod:
1936cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleProjImplicitLod:
1937cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleProjExplicitLod:
1938cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleProjDrefImplicitLod:
1939cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleProjDrefExplicitLod:
1940cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseFetch:
1941cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseGather:
1942cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseDrefGather:
1943cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageTexelPointer:
1944cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            worklist.insert(insn.word(3));  // Image or sampled image
1945cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
1946cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageWrite:
1947cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            worklist.insert(insn.word(1));  // Image -- different operand order to above
1948cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
1949cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpFunctionCall:
1950cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            for (uint32_t i = 3; i < insn.len(); i++) {
1951cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                worklist.insert(insn.word(i));  // fn itself, and all args
1952cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            }
1953cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
19545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1955cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpExtInst:
1956cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            for (uint32_t i = 5; i < insn.len(); i++) {
1957cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                worklist.insert(insn.word(i));  // Operands to ext inst
1958cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            }
1959cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
19605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
19615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
1962cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
19635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
19645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
19653a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
19663a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    return ids;
19675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
19685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1969edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_push_constant_block_against_pipeline(debug_report_data *report_data,
1970416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis                                                          std::vector<VkPushConstantRange> const *push_constant_ranges,
19715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                          shader_module const *src, spirv_inst_iter type,
19725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                          VkShaderStageFlagBits stage) {
19735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool pass = true;
19745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
197525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Strip off ptrs etc
19765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    type = get_struct_type(src, type, false);
19775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(type != src->end());
19785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
197925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Validate directly off the offsets. this isn't quite correct for arrays and matrices, but is a good first step.
198025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // TODO: arrays, matrices, weird sizes
19815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
19825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
19835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(3) == spv::DecorationOffset) {
19845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                unsigned offset = insn.word(4);
1985cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto size = 4;  // Bytes; TODO: calculate this based on the type
19865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
19875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                bool found_range = false;
1988416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis                for (auto const &range : *push_constant_ranges) {
19895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    if (range.offset <= offset && range.offset + range.size >= offset + size) {
19905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        found_range = true;
19915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
19925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        if ((range.stageFlags & stage) == 0) {
1993bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
1994bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        SHADER_CHECKER_PUSH_CONSTANT_NOT_ACCESSIBLE_FROM_STAGE, "SC",
19955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                        "Push constant range covering variable starting at "
19965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                        "offset %u not accessible from stage %s",
19975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                        offset, string_VkShaderStageFlagBits(stage))) {
19985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                pass = false;
19995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                            }
20005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        }
20015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        break;
20035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
20045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
20055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (!found_range) {
2007bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
2008bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                SHADER_CHECKER_PUSH_CONSTANT_OUT_OF_RANGE, "SC",
20095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                "Push constant range covering variable starting at "
20105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                "offset %u not declared in layout",
20115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                offset)) {
20125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        pass = false;
20135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
20145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
20155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
20165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
20175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
20185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return pass;
20205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
20215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2022edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_push_constant_usage(debug_report_data *report_data,
2023416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis                                         std::vector<VkPushConstantRange> const *push_constant_ranges, shader_module const *src,
20245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                         std::unordered_set<uint32_t> accessible_ids, VkShaderStageFlagBits stage) {
20255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool pass = true;
20265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto id : accessible_ids) {
20285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto def_insn = src->get_def(id);
20295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (def_insn.opcode() == spv::OpVariable && def_insn.word(3) == spv::StorageClassPushConstant) {
2030416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis            pass &= validate_push_constant_block_against_pipeline(report_data, push_constant_ranges, src,
2031416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis                                                                  src->get_def(def_insn.word(1)), stage);
20325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
20335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
20345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return pass;
20365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
20375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2038fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis// For given pipelineLayout verify that the set_layout_node at slot.first
2039fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis//  has the requested binding at slot.second and return ptr to that binding
2040bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic VkDescriptorSetLayoutBinding const *get_descriptor_binding(PIPELINE_LAYOUT_NODE const *pipelineLayout,
2041bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                  descriptor_slot_t slot) {
2042cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!pipelineLayout) return nullptr;
20435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2044cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (slot.first >= pipelineLayout->set_layouts.size()) return nullptr;
20455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2046416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis    return pipelineLayout->set_layouts[slot.first]->GetDescriptorSetLayoutBindingPtrFromBinding(slot.second);
20475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
20485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Check object status for selected flag state
205051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool validate_status(layer_data *dev_data, GLOBAL_CB_NODE *pNode, CBStatusFlags status_mask, VkFlags msg_flags,
20514f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                            const char *fail_msg, UNIQUE_VALIDATION_ERROR_CODE const msg_code) {
20523d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    if (!(pNode->status & status_mask)) {
20534f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes        char const *const message = validation_error_map[msg_code];
205451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        return log_msg(dev_data->report_data, msg_flags, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
20554f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                       reinterpret_cast<const uint64_t &>(pNode->commandBuffer), __LINE__, msg_code, "DS",
20564f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                       "command buffer object 0x%p: %s. %s.", pNode->commandBuffer, fail_msg, message);
20575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2058e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    return false;
20595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
20605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Retrieve pipeline node ptr for given pipeline object
206251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic PIPELINE_STATE *getPipelineState(layer_data const *dev_data, VkPipeline pipeline) {
206351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->pipelineMap.find(pipeline);
206451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->pipelineMap.end()) {
2065ea8349eeee76ae2859c10870fd8bd9e60309eb28Chris Forbes        return nullptr;
20665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2067ea8349eeee76ae2859c10870fd8bd9e60309eb28Chris Forbes    return it->second;
20685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
20695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20709a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisRENDER_PASS_STATE *GetRenderPassState(layer_data const *dev_data, VkRenderPass renderpass) {
207151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->renderPassMap.find(renderpass);
207251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->renderPassMap.end()) {
207316387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes        return nullptr;
207416387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes    }
2075fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    return it->second.get();
207616387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes}
207716387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes
20789a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisFRAMEBUFFER_STATE *GetFramebufferState(const layer_data *dev_data, VkFramebuffer framebuffer) {
207951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->frameBufferMap.find(framebuffer);
208051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->frameBufferMap.end()) {
2081f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes        return nullptr;
2082f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes    }
208304861caca7eb93a5241b164e8480bb93c826902cTobin Ehlis    return it->second.get();
2084f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes}
2085f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes
20869a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehliscvdescriptorset::DescriptorSetLayout const *GetDescriptorSetLayout(layer_data const *dev_data, VkDescriptorSetLayout dsLayout) {
208751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->descriptorSetLayoutMap.find(dsLayout);
208851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->descriptorSetLayoutMap.end()) {
208911f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes        return nullptr;
209011f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes    }
209111f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes    return it->second;
209211f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes}
209311f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes
209451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic PIPELINE_LAYOUT_NODE const *getPipelineLayout(layer_data const *dev_data, VkPipelineLayout pipeLayout) {
209551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->pipelineLayoutMap.find(pipeLayout);
209651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->pipelineLayoutMap.end()) {
20974a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes        return nullptr;
20984a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes    }
20994a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes    return &it->second;
21004a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes}
21014a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes
2102e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves// Return true if for a given PSO, the given state enum is dynamic, else return false
21034c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic bool isDynamic(const PIPELINE_STATE *pPipeline, const VkDynamicState state) {
21045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pPipeline && pPipeline->graphicsPipelineCI.pDynamicState) {
21055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < pPipeline->graphicsPipelineCI.pDynamicState->dynamicStateCount; i++) {
2106cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (state == pPipeline->graphicsPipelineCI.pDynamicState->pDynamicStates[i]) return true;
21075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
21085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2109e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    return false;
21105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
21115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
21125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Validate state stored as flags at time of draw call
21134f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayesstatic bool validate_draw_state_flags(layer_data *dev_data, GLOBAL_CB_NODE *pCB, const PIPELINE_STATE *pPipe, bool indexed,
21144f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                      UNIQUE_VALIDATION_ERROR_CODE const msg_code) {
21159c4006684a13db43f0dbc8d0015a9ef34872ca09Chris Forbes    bool result = false;
2116ca546210846c65808717f8875deae39bd227c240Tobin Ehlis    if (pPipe->graphicsPipelineCI.pInputAssemblyState &&
2117ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        ((pPipe->graphicsPipelineCI.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST) ||
2118ca546210846c65808717f8875deae39bd227c240Tobin Ehlis         (pPipe->graphicsPipelineCI.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP))) {
21193d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_LINE_WIDTH_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
21204f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic line width state not set for this command buffer", msg_code);
21213d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
212245824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves    if (pPipe->graphicsPipelineCI.pRasterizationState &&
212345824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves        (pPipe->graphicsPipelineCI.pRasterizationState->depthBiasEnable == VK_TRUE)) {
21243d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_DEPTH_BIAS_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
21254f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic depth bias state not set for this command buffer", msg_code);
21263d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
21273d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    if (pPipe->blendConstantsEnabled) {
21283d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_BLEND_CONSTANTS_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
21294f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic blend constants state not set for this command buffer", msg_code);
21303d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
213145824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves    if (pPipe->graphicsPipelineCI.pDepthStencilState &&
213245824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves        (pPipe->graphicsPipelineCI.pDepthStencilState->depthBoundsTestEnable == VK_TRUE)) {
21333d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_DEPTH_BOUNDS_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
21344f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic depth bounds state not set for this command buffer", msg_code);
21353d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
213645824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves    if (pPipe->graphicsPipelineCI.pDepthStencilState &&
213745824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves        (pPipe->graphicsPipelineCI.pDepthStencilState->stencilTestEnable == VK_TRUE)) {
21383d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_STENCIL_READ_MASK_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
21394f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic stencil read mask state not set for this command buffer", msg_code);
21403d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_STENCIL_WRITE_MASK_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
21414f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic stencil write mask state not set for this command buffer", msg_code);
21423d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_STENCIL_REFERENCE_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
21434f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic stencil reference state not set for this command buffer", msg_code);
21443d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
21451c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    if (indexed) {
21463d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_INDEX_BUFFER_BOUND, VK_DEBUG_REPORT_ERROR_BIT_EXT,
21474f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Index buffer object not bound to this command buffer when Indexed Draw attempted", msg_code);
21483d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
21494f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes
21505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
21515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
21525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
21535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Verify attachment reference compatibility according to spec
21545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  If one array is larger, treat missing elements of shorter array as VK_ATTACHMENT_UNUSED & other array much match this
21555ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski//  If both AttachmentReference arrays have requested index, check their corresponding AttachmentDescriptions
21565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//   to make sure that format and samples counts match.
21575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  If not, they are not compatible.
21585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic bool attachment_references_compatible(const uint32_t index, const VkAttachmentReference *pPrimary,
21595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                             const uint32_t primaryCount, const VkAttachmentDescription *pPrimaryAttachments,
21605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                             const VkAttachmentReference *pSecondary, const uint32_t secondaryCount,
21615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                             const VkAttachmentDescription *pSecondaryAttachments) {
2162e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis    // Check potential NULL cases first to avoid nullptr issues later
2163e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis    if (pPrimary == nullptr) {
2164e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis        if (pSecondary == nullptr) {
2165e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis            return true;
2166e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis        }
2167e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis        return false;
2168e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis    } else if (pSecondary == nullptr) {
2169e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis        return false;
2170e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis    }
2171cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (index >= primaryCount) {  // Check secondary as if primary is VK_ATTACHMENT_UNUSED
2172cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (VK_ATTACHMENT_UNUSED == pSecondary[index].attachment) return true;
2173cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    } else if (index >= secondaryCount) {  // Check primary as if secondary is VK_ATTACHMENT_UNUSED
2174cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (VK_ATTACHMENT_UNUSED == pPrimary[index].attachment) return true;
2175cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    } else {  // Format and sample count must match
21765ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski        if ((pPrimary[index].attachment == VK_ATTACHMENT_UNUSED) && (pSecondary[index].attachment == VK_ATTACHMENT_UNUSED)) {
21775ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski            return true;
21785ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski        } else if ((pPrimary[index].attachment == VK_ATTACHMENT_UNUSED) || (pSecondary[index].attachment == VK_ATTACHMENT_UNUSED)) {
21795ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski            return false;
21805ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski        }
21815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if ((pPrimaryAttachments[pPrimary[index].attachment].format ==
21825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis             pSecondaryAttachments[pSecondary[index].attachment].format) &&
21835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            (pPrimaryAttachments[pPrimary[index].attachment].samples ==
21845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis             pSecondaryAttachments[pSecondary[index].attachment].samples))
21855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return true;
21865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
21875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Format and sample counts didn't match
21885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return false;
21895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
2190a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis// TODO : Scrub verify_renderpass_compatibility() and validateRenderPassCompatibility() and unify them and/or share code
21918da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis// For given primary RenderPass object and secondry RenderPassCreateInfo, verify that they're compatible
219251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool verify_renderpass_compatibility(const layer_data *dev_data, const VkRenderPassCreateInfo *primaryRPCI,
21938da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis                                            const VkRenderPassCreateInfo *secondaryRPCI, string &errorMsg) {
21945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (primaryRPCI->subpassCount != secondaryRPCI->subpassCount) {
2195c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes        stringstream errorStr;
21965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        errorStr << "RenderPass for primary cmdBuffer has " << primaryRPCI->subpassCount
21975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                 << " subpasses but renderPass for secondary cmdBuffer has " << secondaryRPCI->subpassCount << " subpasses.";
21985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        errorMsg = errorStr.str();
21995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return false;
22005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
22015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t spIndex = 0;
22025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (spIndex = 0; spIndex < primaryRPCI->subpassCount; ++spIndex) {
22035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // For each subpass, verify that corresponding color, input, resolve & depth/stencil attachment references are compatible
22045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primaryColorCount = primaryRPCI->pSubpasses[spIndex].colorAttachmentCount;
22055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t secondaryColorCount = secondaryRPCI->pSubpasses[spIndex].colorAttachmentCount;
22065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t colorMax = std::max(primaryColorCount, secondaryColorCount);
22075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t cIdx = 0; cIdx < colorMax; ++cIdx) {
22085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!attachment_references_compatible(cIdx, primaryRPCI->pSubpasses[spIndex].pColorAttachments, primaryColorCount,
22095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                  primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pColorAttachments,
22105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                  secondaryColorCount, secondaryRPCI->pAttachments)) {
2211c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes                stringstream errorStr;
22125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorStr << "color attachments at index " << cIdx << " of subpass index " << spIndex << " are not compatible.";
22135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorMsg = errorStr.str();
22145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return false;
22155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else if (!attachment_references_compatible(cIdx, primaryRPCI->pSubpasses[spIndex].pResolveAttachments,
22165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                         primaryColorCount, primaryRPCI->pAttachments,
22175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                         secondaryRPCI->pSubpasses[spIndex].pResolveAttachments,
22185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                         secondaryColorCount, secondaryRPCI->pAttachments)) {
2219c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes                stringstream errorStr;
22205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorStr << "resolve attachments at index " << cIdx << " of subpass index " << spIndex << " are not compatible.";
22215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorMsg = errorStr.str();
22225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return false;
22235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
22245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
2225fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes
2226bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        if (!attachment_references_compatible(0, primaryRPCI->pSubpasses[spIndex].pDepthStencilAttachment, 1,
2227bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pDepthStencilAttachment,
2228fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes                                              1, secondaryRPCI->pAttachments)) {
2229c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes            stringstream errorStr;
2230fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes            errorStr << "depth/stencil attachments of subpass index " << spIndex << " are not compatible.";
2231fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes            errorMsg = errorStr.str();
2232fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes            return false;
2233fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes        }
2234fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes
22355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primaryInputCount = primaryRPCI->pSubpasses[spIndex].inputAttachmentCount;
22365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t secondaryInputCount = secondaryRPCI->pSubpasses[spIndex].inputAttachmentCount;
22375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t inputMax = std::max(primaryInputCount, secondaryInputCount);
22385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < inputMax; ++i) {
22395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!attachment_references_compatible(i, primaryRPCI->pSubpasses[spIndex].pInputAttachments, primaryColorCount,
22405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                  primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pInputAttachments,
22415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                  secondaryColorCount, secondaryRPCI->pAttachments)) {
2242c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes                stringstream errorStr;
22435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorStr << "input attachments at index " << i << " of subpass index " << spIndex << " are not compatible.";
22445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorMsg = errorStr.str();
22455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return false;
22465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
22475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
22485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
22495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return true;
22505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
22515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2252397d27da37095073c8b86f9ff5289d0a39ce486eTobin Ehlis// For given cvdescriptorset::DescriptorSet, verify that its Set is compatible w/ the setLayout corresponding to
2253397d27da37095073c8b86f9ff5289d0a39ce486eTobin Ehlis// pipelineLayout[layoutIndex]
225451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool verify_set_layout_compatibility(layer_data *dev_data, const cvdescriptorset::DescriptorSet *descriptor_set,
225569b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                                            PIPELINE_LAYOUT_NODE const *pipeline_layout, const uint32_t layoutIndex,
225669b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                                            string &errorMsg) {
2257416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis    auto num_sets = pipeline_layout->set_layouts.size();
22589b5d124aff50234cb0450e1b805baef577c90d83Tobin Ehlis    if (layoutIndex >= num_sets) {
2259c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes        stringstream errorStr;
226069b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis        errorStr << "VkPipelineLayout (" << pipeline_layout->layout << ") only contains " << num_sets
226169b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                 << " setLayouts corresponding to sets 0-" << num_sets - 1 << ", but you're attempting to bind set to index "
226269b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                 << layoutIndex;
22635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        errorMsg = errorStr.str();
22645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return false;
22655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2266416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis    auto layout_node = pipeline_layout->set_layouts[layoutIndex];
22671c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    return descriptor_set->IsCompatible(layout_node, &errorMsg);
22685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
22695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
22705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Validate that data for each specialization entry is fully contained within the buffer.
2271edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_specialization_offsets(debug_report_data *report_data, VkPipelineShaderStageCreateInfo const *info) {
2272e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool pass = true;
22735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
22745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkSpecializationInfo const *spec = info->pSpecializationInfo;
22755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
22765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (spec) {
22775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto i = 0u; i < spec->mapEntryCount; i++) {
22784f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes            // TODO: This is a good place for VALIDATION_ERROR_00589.
22795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (spec->pMapEntries[i].offset + spec->pMapEntries[i].size > spec->dataSize) {
22804f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
22814f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                            VALIDATION_ERROR_00590, "SC",
22825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                            "Specialization entry %u (for constant id %u) references memory outside provided "
22835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                            "specialization data (bytes %u.." PRINTF_SIZE_T_SPECIFIER "; " PRINTF_SIZE_T_SPECIFIER
22844f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                            " bytes provided). %s.",
22855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                            i, spec->pMapEntries[i].constantID, spec->pMapEntries[i].offset,
22864f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                            spec->pMapEntries[i].offset + spec->pMapEntries[i].size - 1, spec->dataSize,
22874f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                            validation_error_map[VALIDATION_ERROR_00590])) {
2288e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                    pass = false;
22895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
22905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
22915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
22925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
22935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
22945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return pass;
22955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
22965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2297bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool descriptor_type_match(shader_module const *module, uint32_t type_id, VkDescriptorType descriptor_type,
2298bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                  unsigned &descriptor_count) {
22995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto type = module->get_def(type_id);
23005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
23011b8c581791ac3c05d7829e04a2d8ecb964b8f2a6Chris Forbes    descriptor_count = 1;
23021b8c581791ac3c05d7829e04a2d8ecb964b8f2a6Chris Forbes
230325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Strip off any array or ptrs. Where we remove array levels, adjust the  descriptor count for each dimension.
23045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while (type.opcode() == spv::OpTypeArray || type.opcode() == spv::OpTypePointer) {
23057b892d2fc502b57d26dc9bff61b0f23cccc595fdChris Forbes        if (type.opcode() == spv::OpTypeArray) {
23067b892d2fc502b57d26dc9bff61b0f23cccc595fdChris Forbes            descriptor_count *= get_constant_value(module, type.word(3));
23077b892d2fc502b57d26dc9bff61b0f23cccc595fdChris Forbes            type = module->get_def(type.word(2));
2308bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        } else {
23097b892d2fc502b57d26dc9bff61b0f23cccc595fdChris Forbes            type = module->get_def(type.word(3));
23107b892d2fc502b57d26dc9bff61b0f23cccc595fdChris Forbes        }
23115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
23125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
23135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (type.opcode()) {
2314cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeStruct: {
2315cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            for (auto insn : *module) {
2316cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (insn.opcode() == spv::OpDecorate && insn.word(1) == type.word(1)) {
2317cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    if (insn.word(2) == spv::DecorationBlock) {
2318cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ||
2319cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                               descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
2320cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    } else if (insn.word(2) == spv::DecorationBufferBlock) {
2321cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ||
2322cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                               descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
2323cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    }
23245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
23255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
23265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2327cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Invalid
2328cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return false;
2329cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
23305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2331cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeSampler:
2332cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return descriptor_type == VK_DESCRIPTOR_TYPE_SAMPLER || descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
23335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2334cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeSampledImage:
2335cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) {
2336cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // Slight relaxation for some GLSL historical madness: samplerBuffer doesn't really have a sampler, and a texel
2337cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // buffer descriptor doesn't really provide one. Allow this slight mismatch.
2338cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto image_type = module->get_def(type.word(2));
2339cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto dim = image_type.word(3);
2340cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto sampled = image_type.word(7);
2341cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return dim == spv::DimBuffer && sampled == 1;
2342cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
2343cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
23445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2345cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeImage: {
2346cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Many descriptor types backing image types-- depends on dimension and whether the image will be used with a sampler.
2347cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // SPIRV for Vulkan requires that sampled be 1 or 2 -- leaving the decision to runtime is unacceptable.
2348cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            auto dim = type.word(3);
2349cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            auto sampled = type.word(7);
23505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2351cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (dim == spv::DimSubpassData) {
2352cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return descriptor_type == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
2353cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else if (dim == spv::DimBuffer) {
2354cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (sampled == 1) {
2355cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    return descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
2356cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                } else {
2357cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
2358cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
2359cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else if (sampled == 1) {
2360cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return descriptor_type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ||
2361cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                       descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
23625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else {
2363cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
23645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
23655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
23665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2367cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        // We shouldn't really see any other junk types -- but if we do, they're a mismatch.
2368cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
2369cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return false;  // Mismatch
23705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
23715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
23725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
23734110a6be7a8a287d459475926985f71c27d01298Chris Forbesstatic bool require_feature(debug_report_data *report_data, VkBool32 feature, char const *feature_name) {
2374a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    if (!feature) {
2375bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
2376cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    SHADER_CHECKER_FEATURE_NOT_ENABLED, "SC",
2377cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "Shader requires VkPhysicalDeviceFeatures::%s but is not "
2378cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "enabled on the device",
2379a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes                    feature_name)) {
2380a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes            return false;
2381a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes        }
2382a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    }
2383a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2384a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    return true;
2385a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes}
2386a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
23877b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbesstatic bool require_extension(debug_report_data *report_data, VkBool32 extension, char const *extension_name) {
23887b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes    if (!extension) {
23897b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes        if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
23907b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes                    SHADER_CHECKER_FEATURE_NOT_ENABLED, "SC",
23917b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes                    "Shader requires extension %s but is not "
23927b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes                    "enabled on the device",
23937b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes                    extension_name)) {
23947b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes            return false;
23957b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes        }
23967b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes    }
23977b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes
23987b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes    return true;
23997b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes}
24007b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes
2401ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbesstatic bool validate_shader_capabilities(layer_data *dev_data, shader_module const *src) {
2402e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool pass = true;
2403a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2404ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes    auto report_data = dev_data->report_data;
2405ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes    auto const & enabledFeatures = dev_data->enabled_features;
2406ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes
2407a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    for (auto insn : *src) {
2408a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes        if (insn.opcode() == spv::OpCapability) {
2409a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes            switch (insn.word(1)) {
2410cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityMatrix:
2411cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityShader:
2412cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityInputAttachment:
2413cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilitySampled1D:
2414cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityImage1D:
2415cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilitySampledBuffer:
2416cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityImageBuffer:
2417cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityImageQuery:
2418cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityDerivativeControl:
2419cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    // Always supported by a Vulkan 1.0 implementation -- no feature bits.
2420cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2421a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2422cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityGeometry:
2423ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes                    pass &= require_feature(report_data, enabledFeatures.geometryShader, "geometryShader");
2424cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2425a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2426cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityTessellation:
2427ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes                    pass &= require_feature(report_data, enabledFeatures.tessellationShader, "tessellationShader");
2428cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2429a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2430cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityFloat64:
2431ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes                    pass &= require_feature(report_data, enabledFeatures.shaderFloat64, "shaderFloat64");
2432cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2433a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2434cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityInt64:
2435ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes                    pass &= require_feature(report_data, enabledFeatures.shaderInt64, "shaderInt64");
2436cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2437a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2438cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityTessellationPointSize:
2439cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityGeometryPointSize:
2440ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes                    pass &= require_feature(report_data, enabledFeatures.shaderTessellationAndGeometryPointSize,
2441cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderTessellationAndGeometryPointSize");
2442cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2443a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2444cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityImageGatherExtended:
2445ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes                    pass &= require_feature(report_data, enabledFeatures.shaderImageGatherExtended, "shaderImageGatherExtended");
2446cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2447a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2448cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityStorageImageMultisample:
2449ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes                    pass &= require_feature(report_data, enabledFeatures.shaderStorageImageMultisample,
2450cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderStorageImageMultisample");
2451cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2452a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2453cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityUniformBufferArrayDynamicIndexing:
2454ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes                    pass &= require_feature(report_data, enabledFeatures.shaderUniformBufferArrayDynamicIndexing,
2455cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderUniformBufferArrayDynamicIndexing");
2456cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2457a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2458cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilitySampledImageArrayDynamicIndexing:
2459ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes                    pass &= require_feature(report_data, enabledFeatures.shaderSampledImageArrayDynamicIndexing,
2460cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderSampledImageArrayDynamicIndexing");
2461cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2462a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2463cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityStorageBufferArrayDynamicIndexing:
2464ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes                    pass &= require_feature(report_data, enabledFeatures.shaderStorageBufferArrayDynamicIndexing,
2465cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderStorageBufferArrayDynamicIndexing");
2466cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2467a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2468cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityStorageImageArrayDynamicIndexing:
2469ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes                    pass &= require_feature(report_data, enabledFeatures.shaderStorageImageArrayDynamicIndexing,
2470cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderStorageImageArrayDynamicIndexing");
2471cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2472a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2473cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityClipDistance:
2474ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes                    pass &= require_feature(report_data, enabledFeatures.shaderClipDistance, "shaderClipDistance");
2475cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2476a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2477cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityCullDistance:
2478ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes                    pass &= require_feature(report_data, enabledFeatures.shaderCullDistance, "shaderCullDistance");
2479cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2480a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2481cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityImageCubeArray:
2482ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes                    pass &= require_feature(report_data, enabledFeatures.imageCubeArray, "imageCubeArray");
2483cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2484a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2485cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilitySampleRateShading:
2486ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes                    pass &= require_feature(report_data, enabledFeatures.sampleRateShading, "sampleRateShading");
2487cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2488a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2489cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilitySparseResidency:
2490ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes                    pass &= require_feature(report_data, enabledFeatures.shaderResourceResidency, "shaderResourceResidency");
2491cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2492a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2493cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityMinLod:
2494ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes                    pass &= require_feature(report_data, enabledFeatures.shaderResourceMinLod, "shaderResourceMinLod");
2495cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2496a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2497cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilitySampledCubeArray:
2498ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes                    pass &= require_feature(report_data, enabledFeatures.imageCubeArray, "imageCubeArray");
2499cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2500a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2501cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityImageMSArray:
2502ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes                    pass &= require_feature(report_data, enabledFeatures.shaderStorageImageMultisample,
2503cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderStorageImageMultisample");
2504cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2505a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2506cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityStorageImageExtendedFormats:
2507ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes                    pass &= require_feature(report_data, enabledFeatures.shaderStorageImageExtendedFormats,
2508cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderStorageImageExtendedFormats");
2509cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2510a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2511cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityInterpolationFunction:
2512ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes                    pass &= require_feature(report_data, enabledFeatures.sampleRateShading, "sampleRateShading");
2513cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2514a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2515cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityStorageImageReadWithoutFormat:
2516ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes                    pass &= require_feature(report_data, enabledFeatures.shaderStorageImageReadWithoutFormat,
2517cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderStorageImageReadWithoutFormat");
2518cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2519a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2520cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityStorageImageWriteWithoutFormat:
2521ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes                    pass &= require_feature(report_data, enabledFeatures.shaderStorageImageWriteWithoutFormat,
2522cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                            "shaderStorageImageWriteWithoutFormat");
2523cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2524a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2525cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case spv::CapabilityMultiViewport:
2526ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes                    pass &= require_feature(report_data, enabledFeatures.multiViewport, "multiViewport");
2527cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2528a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
25297b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes                case spv::CapabilityDrawParameters:
25307b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes                    pass &= require_extension(report_data, dev_data->device_extensions.khr_shader_draw_parameters_enabled,
25317b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes                                              VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME);
25327b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes                    break;
25337b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes
25342664122d97c3f0a98b3e5d12833bbb20196ca837Mark Lobodzinski                case spv::CapabilityGeometryShaderPassthroughNV:
25352664122d97c3f0a98b3e5d12833bbb20196ca837Mark Lobodzinski                    pass &= require_extension(report_data, dev_data->device_extensions.nv_geometry_shader_passthrough_enabled,
25362664122d97c3f0a98b3e5d12833bbb20196ca837Mark Lobodzinski                                              VK_NV_GEOMETRY_SHADER_PASSTHROUGH_EXTENSION_NAME);
25372664122d97c3f0a98b3e5d12833bbb20196ca837Mark Lobodzinski                    break;
25382664122d97c3f0a98b3e5d12833bbb20196ca837Mark Lobodzinski
2539cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                default:
2540436434eba4d9f91016f313c8fb1525d76d7932fcMark Lobodzinski                    // Spirv-validator should catch these errors
2541cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
2542a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes            }
2543a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes        }
2544a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    }
2545a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2546a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    return pass;
2547a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes}
2548a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2549b2a61f3cd17c68887759817059fa1872f1e1464aChris Forbesstatic uint32_t descriptor_type_to_reqs(shader_module const *module, uint32_t type_id) {
25502aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes    auto type = module->get_def(type_id);
25512aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes
25522aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes    while (true) {
25532aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes        switch (type.opcode()) {
2554cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeArray:
2555cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeSampledImage:
2556cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                type = module->get_def(type.word(2));
2557cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
2558cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypePointer:
2559cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                type = module->get_def(type.word(3));
2560cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
2561cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeImage: {
2562cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto dim = type.word(3);
2563cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto arrayed = type.word(5);
2564cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto msaa = type.word(6);
2565cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski
2566cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                switch (dim) {
2567cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    case spv::Dim1D:
2568cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return arrayed ? DESCRIPTOR_REQ_VIEW_TYPE_1D_ARRAY : DESCRIPTOR_REQ_VIEW_TYPE_1D;
2569cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    case spv::Dim2D:
2570cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return (msaa ? DESCRIPTOR_REQ_MULTI_SAMPLE : DESCRIPTOR_REQ_SINGLE_SAMPLE) |
2571cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                               (arrayed ? DESCRIPTOR_REQ_VIEW_TYPE_2D_ARRAY : DESCRIPTOR_REQ_VIEW_TYPE_2D);
2572cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    case spv::Dim3D:
2573cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return DESCRIPTOR_REQ_VIEW_TYPE_3D;
2574cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    case spv::DimCube:
2575cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return arrayed ? DESCRIPTOR_REQ_VIEW_TYPE_CUBE_ARRAY : DESCRIPTOR_REQ_VIEW_TYPE_CUBE;
2576cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    case spv::DimSubpassData:
2577cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return msaa ? DESCRIPTOR_REQ_MULTI_SAMPLE : DESCRIPTOR_REQ_SINGLE_SAMPLE;
2578cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    default:  // buffer, etc.
2579cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return 0;
2580cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
25812aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes            }
2582cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
2583cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return 0;
25842aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes        }
25852aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes    }
2586b2a61f3cd17c68887759817059fa1872f1e1464aChris Forbes}
2587b2a61f3cd17c68887759817059fa1872f1e1464aChris Forbes
2588cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskistatic bool validate_pipeline_shader_stage(
2589ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes    layer_data *dev_data, VkPipelineShaderStageCreateInfo const *pStage, PIPELINE_STATE *pipeline,
2590ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes    shader_module **out_module, spirv_inst_iter *out_entrypoint) {
2591e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool pass = true;
2592ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes    auto module_it = dev_data->shaderModuleMap.find(pStage->module);
259369f9a551bfb1fd5334950f9685c12c5adda23dfbChris Forbes    auto module = *out_module = module_it->second.get();
2594ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes    auto report_data = dev_data->report_data;
259578be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
2596c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski    if (!module->has_valid_spirv) return pass;
2597c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski
259825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Find the entrypoint
259978be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    auto entrypoint = *out_entrypoint = find_entrypoint(module, pStage->pName, pStage->stage);
260078be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    if (entrypoint == module->end()) {
2601ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__, VALIDATION_ERROR_00510,
26024f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                    "SC", "No entrypoint found named `%s` for stage %s. %s.", pStage->pName,
26034f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                    string_VkShaderStageFlagBits(pStage->stage), validation_error_map[VALIDATION_ERROR_00510])) {
2604cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return false;  // no point continuing beyond here, any analysis is just going to be garbage.
260578be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        }
260678be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    }
260778be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
260825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Validate shader capabilities against enabled device features
2609ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes    pass &= validate_shader_capabilities(dev_data, module);
261078be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
261125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Mark accessible ids
26123a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    auto accessible_ids = mark_accessible_ids(module, entrypoint);
261378be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
261425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Validate descriptor set layout against what the entrypoint actually uses
26153a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    auto descriptor_uses = collect_interface_by_descriptor_slot(report_data, module, accessible_ids);
261678be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
26172e0eca3d6fad72a29ae072e3895e29a2d2d66476Tobin Ehlis    auto pipelineLayout = pipeline->pipeline_layout;
2618ed399f66e0512ef077d0e0a7cb903248726d2424Chris Forbes
26190cfa9c3a1747749777581684536218f83c3977a9Chris Forbes    pass &= validate_specialization_offsets(report_data, pStage);
2620416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis    pass &= validate_push_constant_usage(report_data, &pipelineLayout.push_constant_ranges, module, accessible_ids, pStage->stage);
262178be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
262225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Validate descriptor use
262378be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    for (auto use : descriptor_uses) {
262478be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        // While validating shaders capture which slots are used by the pipeline
2625bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto &reqs = pipeline->active_slots[use.first.first][use.first.second];
2626b2a61f3cd17c68887759817059fa1872f1e1464aChris Forbes        reqs = descriptor_req(reqs | descriptor_type_to_reqs(module, use.second.type_id));
262778be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
262825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Verify given pipelineLayout has requested setLayout with requested binding
2629c8268861aaa8f9c47920065d6323e4609e5081b0Tobin Ehlis        const auto &binding = get_descriptor_binding(&pipelineLayout, use.first);
263078be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        unsigned required_descriptor_count;
263178be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
263278be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        if (!binding) {
2633bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
2634bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        SHADER_CHECKER_MISSING_DESCRIPTOR, "SC",
263578be5018e238bd464b1f1c55138df277c0c18922Chris Forbes                        "Shader uses descriptor slot %u.%u (used as type `%s`) but not declared in pipeline layout",
263678be5018e238bd464b1f1c55138df277c0c18922Chris Forbes                        use.first.first, use.first.second, describe_type(module, use.second.type_id).c_str())) {
2637e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                pass = false;
263878be5018e238bd464b1f1c55138df277c0c18922Chris Forbes            }
263978be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        } else if (~binding->stageFlags & pStage->stage) {
2640bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
2641cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        SHADER_CHECKER_DESCRIPTOR_NOT_ACCESSIBLE_FROM_STAGE, "SC",
2642cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "Shader uses descriptor slot %u.%u (used "
2643cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "as type `%s`) but descriptor not "
2644cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "accessible from stage %s",
2645fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis                        use.first.first, use.first.second, describe_type(module, use.second.type_id).c_str(),
264678be5018e238bd464b1f1c55138df277c0c18922Chris Forbes                        string_VkShaderStageFlagBits(pStage->stage))) {
2647e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                pass = false;
264878be5018e238bd464b1f1c55138df277c0c18922Chris Forbes            }
2649bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        } else if (!descriptor_type_match(module, use.second.type_id, binding->descriptorType, required_descriptor_count)) {
2650557cdd5218accf51ca894a14b7c6eeeb733f5cbbChris Forbes            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
2651cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        SHADER_CHECKER_DESCRIPTOR_TYPE_MISMATCH, "SC",
2652cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "Type mismatch on descriptor slot "
2653cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "%u.%u (used as type `%s`) but "
2654cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "descriptor of type %s",
2655fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis                        use.first.first, use.first.second, describe_type(module, use.second.type_id).c_str(),
265678be5018e238bd464b1f1c55138df277c0c18922Chris Forbes                        string_VkDescriptorType(binding->descriptorType))) {
2657e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                pass = false;
265878be5018e238bd464b1f1c55138df277c0c18922Chris Forbes            }
265978be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        } else if (binding->descriptorCount < required_descriptor_count) {
2660557cdd5218accf51ca894a14b7c6eeeb733f5cbbChris Forbes            if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
2661fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis                        SHADER_CHECKER_DESCRIPTOR_TYPE_MISMATCH, "SC",
266278be5018e238bd464b1f1c55138df277c0c18922Chris Forbes                        "Shader expects at least %u descriptors for binding %u.%u (used as type `%s`) but only %u provided",
266378be5018e238bd464b1f1c55138df277c0c18922Chris Forbes                        required_descriptor_count, use.first.first, use.first.second,
2664fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis                        describe_type(module, use.second.type_id).c_str(), binding->descriptorCount)) {
2665e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                pass = false;
266678be5018e238bd464b1f1c55138df277c0c18922Chris Forbes            }
266778be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        }
266878be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    }
266978be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
267025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Validate use of input attachments against subpass structure
2671c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes    if (pStage->stage == VK_SHADER_STAGE_FRAGMENT_BIT) {
26723a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes        auto input_attachment_uses = collect_interface_by_input_attachment_index(report_data, module, accessible_ids);
2673c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes
2674c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes        auto rpci = pipeline->render_pass_ci.ptr();
2675c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes        auto subpass = pipeline->graphicsPipelineCI.subpass;
2676c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes
2677c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes        for (auto use : input_attachment_uses) {
2678c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes            auto input_attachments = rpci->pSubpasses[subpass].pInputAttachments;
2679bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            auto index = (input_attachments && use.first < rpci->pSubpasses[subpass].inputAttachmentCount)
2680bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             ? input_attachments[use.first].attachment
2681bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             : VK_ATTACHMENT_UNUSED;
2682c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes
2683c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes            if (index == VK_ATTACHMENT_UNUSED) {
2684c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
2685c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes                            SHADER_CHECKER_MISSING_INPUT_ATTACHMENT, "SC",
2686bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "Shader consumes input attachment index %d but not provided in subpass", use.first)) {
2687c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes                    pass = false;
2688c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes                }
2689f0fdde7692ffd5175435cc3bf3412b8468054f38Chris Forbes            } else if (!(get_format_type(rpci->pAttachments[index].format) & get_fundamental_type(module, use.second.type_id))) {
2690eeb9f6a27f1acc11e54080fb3bcda7b513b5c89fChris Forbes                if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
2691eeb9f6a27f1acc11e54080fb3bcda7b513b5c89fChris Forbes                            SHADER_CHECKER_INPUT_ATTACHMENT_TYPE_MISMATCH, "SC",
2692bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "Subpass input attachment %u format of %s does not match type used in shader `%s`", use.first,
2693bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            string_VkFormat(rpci->pAttachments[index].format), describe_type(module, use.second.type_id).c_str())) {
2694eeb9f6a27f1acc11e54080fb3bcda7b513b5c89fChris Forbes                    pass = false;
2695eeb9f6a27f1acc11e54080fb3bcda7b513b5c89fChris Forbes                }
2696eeb9f6a27f1acc11e54080fb3bcda7b513b5c89fChris Forbes            }
2697c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes        }
2698c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes    }
2699c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes
270078be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    return pass;
270178be5018e238bd464b1f1c55138df277c0c18922Chris Forbes}
270278be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
2703a61b537fcb6a4f7b92cd217b3964ad7a48109da1Tobin Ehlis// Validate that the shaders used by the given pipeline and store the active_slots
2704a61b537fcb6a4f7b92cd217b3964ad7a48109da1Tobin Ehlis//  that are actually used by the pipeline into pPipeline->active_slots
2705ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbesstatic bool validate_and_capture_pipeline_shader_state(layer_data *dev_data, PIPELINE_STATE *pPipeline) {
27066660d6f3e4e4c895063e8d99098162bd2f508b24Chris Forbes    auto pCreateInfo = pPipeline->graphicsPipelineCI.ptr();
27075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    int vertex_stage = get_shader_stage_id(VK_SHADER_STAGE_VERTEX_BIT);
27085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    int fragment_stage = get_shader_stage_id(VK_SHADER_STAGE_FRAGMENT_BIT);
27095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    shader_module *shaders[5];
27115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    memset(shaders, 0, sizeof(shaders));
27125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter entrypoints[5];
27135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    memset(entrypoints, 0, sizeof(entrypoints));
2714e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool pass = true;
27155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) {
27176660d6f3e4e4c895063e8d99098162bd2f508b24Chris Forbes        auto pStage = &pCreateInfo->pStages[i];
271878be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        auto stage_id = get_shader_stage_id(pStage->stage);
2719ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes        pass &= validate_pipeline_shader_stage(dev_data, pStage, pPipeline, &shaders[stage_id], &entrypoints[stage_id]);
27205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
27215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2722d5365427feb4a6c16371ecb651afa37b89dabd96Chris Forbes    // if the shader stages are no good individually, cross-stage validation is pointless.
2723cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!pass) return false;
2724b7476f4c4998ae20e579bd2d134667b71acdbf91Chris Forbes
2725ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes    auto vi = pCreateInfo->pVertexInputState;
27265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (vi) {
2728ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes        pass &= validate_vi_consistency(dev_data->report_data, vi);
27295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
27305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2731c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski    if (shaders[vertex_stage] && shaders[vertex_stage]->has_valid_spirv) {
2732ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes        pass &= validate_vi_against_vs_inputs(dev_data->report_data, vi, shaders[vertex_stage], entrypoints[vertex_stage]);
27335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
27345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    int producer = get_shader_stage_id(VK_SHADER_STAGE_VERTEX_BIT);
27365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    int consumer = get_shader_stage_id(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
27375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while (!shaders[producer] && producer != fragment_stage) {
27395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        producer++;
27405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        consumer++;
27415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
27425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (; producer != fragment_stage && consumer <= fragment_stage; consumer++) {
27445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        assert(shaders[producer]);
2745c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski        if (shaders[consumer] && shaders[consumer]->has_valid_spirv && shaders[producer]->has_valid_spirv) {
2746ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes            pass &= validate_interface_between_stages(dev_data->report_data, shaders[producer], entrypoints[producer],
2747bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      &shader_stage_attribs[producer], shaders[consumer], entrypoints[consumer],
2748bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      &shader_stage_attribs[consumer]);
27495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            producer = consumer;
27515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
27525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
27535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2754c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski    if (shaders[fragment_stage] && shaders[fragment_stage]->has_valid_spirv) {
2755ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes        pass &= validate_fs_outputs_against_render_pass(dev_data->report_data, shaders[fragment_stage], entrypoints[fragment_stage],
27568da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis                                                        pPipeline->render_pass_ci.ptr(), pCreateInfo->subpass);
27575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
27585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return pass;
27605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
27615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2762ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbesstatic bool validate_compute_pipeline(layer_data *dev_data, PIPELINE_STATE *pPipeline) {
27636660d6f3e4e4c895063e8d99098162bd2f508b24Chris Forbes    auto pCreateInfo = pPipeline->computePipelineCI.ptr();
276403857e826cdc6e8d814137fb3245596ca1cb7bc7Chris Forbes
276503857e826cdc6e8d814137fb3245596ca1cb7bc7Chris Forbes    shader_module *module;
276603857e826cdc6e8d814137fb3245596ca1cb7bc7Chris Forbes    spirv_inst_iter entrypoint;
276703857e826cdc6e8d814137fb3245596ca1cb7bc7Chris Forbes
2768ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes    return validate_pipeline_shader_stage(dev_data, &pCreateInfo->stage, pPipeline, &module, &entrypoint);
276903857e826cdc6e8d814137fb3245596ca1cb7bc7Chris Forbes}
27705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Return Set node ptr for specified set or else NULL
27719a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehliscvdescriptorset::DescriptorSet *GetSetNode(const layer_data *dev_data, VkDescriptorSet set) {
277251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto set_it = dev_data->setMap.find(set);
277351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (set_it == dev_data->setMap.end()) {
27745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return NULL;
27755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2776104ab082916e41467ef60baaab7a5a8b2e02c59cTobin Ehlis    return set_it->second;
27775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
27785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2779eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young// For given pipeline, return number of MSAA samples, or one if MSAA disabled
27804c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic VkSampleCountFlagBits getNumSamples(PIPELINE_STATE const *pipe) {
2781ea8349eeee76ae2859c10870fd8bd9e60309eb28Chris Forbes    if (pipe->graphicsPipelineCI.pMultisampleState != NULL &&
2782ea8349eeee76ae2859c10870fd8bd9e60309eb28Chris Forbes        VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO == pipe->graphicsPipelineCI.pMultisampleState->sType) {
2783eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young        return pipe->graphicsPipelineCI.pMultisampleState->rasterizationSamples;
2784eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    }
2785eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    return VK_SAMPLE_COUNT_1_BIT;
2786eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young}
2787eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
2788bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic void list_bits(std::ostream &s, uint32_t bits) {
2789b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes    for (int i = 0; i < 32 && bits; i++) {
2790b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes        if (bits & (1 << i)) {
2791b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            s << i;
2792b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            bits &= ~(1 << i);
2793b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            if (bits) {
2794b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                s << ",";
2795b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            }
2796b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes        }
2797b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes    }
2798b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes}
2799b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes
2800eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young// Validate draw-time state related to the PSO
280151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool ValidatePipelineDrawtimeState(layer_data const *dev_data, LAST_BOUND_STATE const &state, const GLOBAL_CB_NODE *pCB,
28024c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis                                          PIPELINE_STATE const *pPipeline) {
2803eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    bool skip_call = false;
280429d196e071b2dc1db47702085469396f2b956820Chris Forbes
2805d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen    // Verify vertex binding
280629d196e071b2dc1db47702085469396f2b956820Chris Forbes    if (pPipeline->vertexBindingDescriptions.size() > 0) {
280729d196e071b2dc1db47702085469396f2b956820Chris Forbes        for (size_t i = 0; i < pPipeline->vertexBindingDescriptions.size(); i++) {
2808312129ec52e6249aa453e27e6be17a8dab1e98b8Tobin Ehlis            auto vertex_binding = pPipeline->vertexBindingDescriptions[i].binding;
2809312129ec52e6249aa453e27e6be17a8dab1e98b8Tobin Ehlis            if ((pCB->currentDrawData.buffers.size() < (vertex_binding + 1)) ||
2810312129ec52e6249aa453e27e6be17a8dab1e98b8Tobin Ehlis                (pCB->currentDrawData.buffers[vertex_binding] == VK_NULL_HANDLE)) {
2811cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                skip_call |=
2812df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2813df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            reinterpret_cast<uint64_t>(pCB->commandBuffer), __LINE__, DRAWSTATE_VTX_INDEX_OUT_OF_BOUNDS, "DS",
2814cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "The Pipeline State Object (0x%" PRIxLEAST64
2815cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            ") expects that this Command Buffer's vertex binding Index %u "
2816cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "should be set via vkCmdBindVertexBuffers. This is because VkVertexInputBindingDescription struct "
2817cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "at index " PRINTF_SIZE_T_SPECIFIER " of pVertexBindingDescriptions has a binding value of %u.",
2818cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            (uint64_t)state.pipeline_state->pipeline, vertex_binding, i, vertex_binding);
281929d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
282029d196e071b2dc1db47702085469396f2b956820Chris Forbes        }
282129d196e071b2dc1db47702085469396f2b956820Chris Forbes    } else {
282258b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis        if (!pCB->currentDrawData.buffers.empty() && !pCB->vertex_buffer_used) {
2823df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
2824df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t>(pCB->commandBuffer),
2825df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                 __LINE__, DRAWSTATE_VTX_INDEX_OUT_OF_BOUNDS, "DS",
2826226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                 "Vertex buffers are bound to command buffer (0x%p"
28275c288f35b2eab0dab95d18768235fef6ffd69b30Tobin Ehlis                                 ") but no vertex buffers are attached to this Pipeline State Object (0x%" PRIxLEAST64 ").",
2828226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                 pCB->commandBuffer, (uint64_t)state.pipeline_state->pipeline);
282929d196e071b2dc1db47702085469396f2b956820Chris Forbes        }
283029d196e071b2dc1db47702085469396f2b956820Chris Forbes    }
283129d196e071b2dc1db47702085469396f2b956820Chris Forbes    // If Viewport or scissors are dynamic, verify that dynamic count matches PSO count.
283229d196e071b2dc1db47702085469396f2b956820Chris Forbes    // Skip check if rasterization is disabled or there is no viewport.
283329d196e071b2dc1db47702085469396f2b956820Chris Forbes    if ((!pPipeline->graphicsPipelineCI.pRasterizationState ||
283429d196e071b2dc1db47702085469396f2b956820Chris Forbes         (pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable == VK_FALSE)) &&
283529d196e071b2dc1db47702085469396f2b956820Chris Forbes        pPipeline->graphicsPipelineCI.pViewportState) {
283629d196e071b2dc1db47702085469396f2b956820Chris Forbes        bool dynViewport = isDynamic(pPipeline, VK_DYNAMIC_STATE_VIEWPORT);
283729d196e071b2dc1db47702085469396f2b956820Chris Forbes        bool dynScissor = isDynamic(pPipeline, VK_DYNAMIC_STATE_SCISSOR);
2838b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes
283929d196e071b2dc1db47702085469396f2b956820Chris Forbes        if (dynViewport) {
2840b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            auto requiredViewportsMask = (1 << pPipeline->graphicsPipelineCI.pViewportState->viewportCount) - 1;
2841b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            auto missingViewportMask = ~pCB->viewportMask & requiredViewportsMask;
2842b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            if (missingViewportMask) {
2843b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                std::stringstream ss;
2844b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                ss << "Dynamic viewport(s) ";
2845b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                list_bits(ss, missingViewportMask);
2846d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen                ss << " are used by pipeline state object, but were not provided via calls to vkCmdSetViewport().";
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        }
2851b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes
285229d196e071b2dc1db47702085469396f2b956820Chris Forbes        if (dynScissor) {
2853b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            auto requiredScissorMask = (1 << pPipeline->graphicsPipelineCI.pViewportState->scissorCount) - 1;
2854b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            auto missingScissorMask = ~pCB->scissorMask & requiredScissorMask;
2855b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            if (missingScissorMask) {
2856b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                std::stringstream ss;
2857b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                ss << "Dynamic scissor(s) ";
2858b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                list_bits(ss, missingScissorMask);
2859d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen                ss << " are used by pipeline state object, but were not provided via calls to vkCmdSetScissor().";
286051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
2861bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                     __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", "%s", ss.str().c_str());
286229d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
286329d196e071b2dc1db47702085469396f2b956820Chris Forbes        }
286429d196e071b2dc1db47702085469396f2b956820Chris Forbes    }
286529d196e071b2dc1db47702085469396f2b956820Chris Forbes
286629d196e071b2dc1db47702085469396f2b956820Chris Forbes    // Verify that any MSAA request in PSO matches sample# in bound FB
286729d196e071b2dc1db47702085469396f2b956820Chris Forbes    // Skip the check if rasterization is disabled.
286829d196e071b2dc1db47702085469396f2b956820Chris Forbes    if (!pPipeline->graphicsPipelineCI.pRasterizationState ||
286929d196e071b2dc1db47702085469396f2b956820Chris Forbes        (pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable == VK_FALSE)) {
287029d196e071b2dc1db47702085469396f2b956820Chris Forbes        VkSampleCountFlagBits pso_num_samples = getNumSamples(pPipeline);
287129d196e071b2dc1db47702085469396f2b956820Chris Forbes        if (pCB->activeRenderPass) {
2872fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes            auto const render_pass_info = pCB->activeRenderPass->createInfo.ptr();
287329d196e071b2dc1db47702085469396f2b956820Chris Forbes            const VkSubpassDescription *subpass_desc = &render_pass_info->pSubpasses[pCB->activeSubpass];
287429d196e071b2dc1db47702085469396f2b956820Chris Forbes            uint32_t i;
287576957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes            unsigned subpass_num_samples = 0;
28760a7ed0466d3d3c6c71be07d66c200482d9a9d073Chris Forbes
287729d196e071b2dc1db47702085469396f2b956820Chris Forbes            for (i = 0; i < subpass_desc->colorAttachmentCount; i++) {
287876957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                auto attachment = subpass_desc->pColorAttachments[i].attachment;
287976957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                if (attachment != VK_ATTACHMENT_UNUSED)
288076957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                    subpass_num_samples |= (unsigned)render_pass_info->pAttachments[attachment].samples;
288129d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
28820a7ed0466d3d3c6c71be07d66c200482d9a9d073Chris Forbes
288376957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes            if (subpass_desc->pDepthStencilAttachment &&
288476957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                subpass_desc->pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
288576957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                auto attachment = subpass_desc->pDepthStencilAttachment->attachment;
288676957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                subpass_num_samples |= (unsigned)render_pass_info->pAttachments[attachment].samples;
288729d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
2888eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
28890dc3fd4e57b8531638781daa01a2fb5d1048a6fbJamie Madill            if (subpass_num_samples && static_cast<unsigned>(pso_num_samples) != subpass_num_samples) {
289029d196e071b2dc1db47702085469396f2b956820Chris Forbes                skip_call |=
289151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2892bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            reinterpret_cast<const uint64_t &>(pPipeline->pipeline), __LINE__, DRAWSTATE_NUM_SAMPLES_MISMATCH, "DS",
2893bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "Num samples mismatch! At draw-time in Pipeline (0x%" PRIxLEAST64
2894bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            ") with %u samples while current RenderPass (0x%" PRIxLEAST64 ") w/ %u samples!",
2895bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            reinterpret_cast<const uint64_t &>(pPipeline->pipeline), pso_num_samples,
2896bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            reinterpret_cast<const uint64_t &>(pCB->activeRenderPass->renderPass), subpass_num_samples);
2897eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young            }
289829d196e071b2dc1db47702085469396f2b956820Chris Forbes        } else {
289951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2900bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 reinterpret_cast<const uint64_t &>(pPipeline->pipeline), __LINE__, DRAWSTATE_NUM_SAMPLES_MISMATCH,
2901bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 "DS", "No active render pass found at draw-time in Pipeline (0x%" PRIxLEAST64 ")!",
290229d196e071b2dc1db47702085469396f2b956820Chris Forbes                                 reinterpret_cast<const uint64_t &>(pPipeline->pipeline));
2903eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young        }
2904eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    }
2905528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis    // Verify that PSO creation renderPass is compatible with active renderPass
2906528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis    if (pCB->activeRenderPass) {
2907528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis        std::string err_string;
2908a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        if ((pCB->activeRenderPass->renderPass != pPipeline->graphicsPipelineCI.renderPass) &&
290951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            !verify_renderpass_compatibility(dev_data, pCB->activeRenderPass->createInfo.ptr(), pPipeline->render_pass_ci.ptr(),
2910528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis                                             err_string)) {
2911528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis            // renderPass that PSO was created with must be compatible with active renderPass that PSO is being used with
2912528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis            skip_call |=
291351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2914528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis                        reinterpret_cast<const uint64_t &>(pPipeline->pipeline), __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE, "DS",
2915cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "At Draw time the active render pass (0x%" PRIxLEAST64
2916cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        ") is incompatible w/ gfx pipeline "
2917528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis                        "(0x%" PRIxLEAST64 ") that was created w/ render pass (0x%" PRIxLEAST64 ") due to: %s",
29186de0e43adfbd3c049252412d998524e7edbd3796Chris Forbes                        reinterpret_cast<uint64_t &>(pCB->activeRenderPass->renderPass),
29196de0e43adfbd3c049252412d998524e7edbd3796Chris Forbes                        reinterpret_cast<uint64_t const &>(pPipeline->pipeline),
2920528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis                        reinterpret_cast<const uint64_t &>(pPipeline->graphicsPipelineCI.renderPass), err_string.c_str());
2921528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis        }
2922c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes
2923c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes        if (pPipeline->graphicsPipelineCI.subpass != pCB->activeSubpass) {
2924c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes            skip_call |=
292551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2926c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes                        reinterpret_cast<uint64_t const &>(pPipeline->pipeline), __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE, "DS",
2927c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes                        "Pipeline was built for subpass %u but used in subpass %u", pPipeline->graphicsPipelineCI.subpass,
2928c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes                        pCB->activeSubpass);
2929c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes        }
2930528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis    }
293129d196e071b2dc1db47702085469396f2b956820Chris Forbes    // TODO : Add more checks here
293229d196e071b2dc1db47702085469396f2b956820Chris Forbes
2933eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    return skip_call;
2934eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young}
2935eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
29365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Validate overall state at the time of a draw call
293751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool ValidateDrawState(layer_data *dev_data, GLOBAL_CB_NODE *cb_node, const bool indexed,
29384f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                              const VkPipelineBindPoint bind_point, const char *function,
29394f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                              UNIQUE_VALIDATION_ERROR_CODE const msg_code) {
2940e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool result = false;
29411c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    auto const &state = cb_node->lastBound[bind_point];
29424c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    PIPELINE_STATE *pPipe = state.pipeline_state;
294322fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis    if (nullptr == pPipe) {
294422fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis        result |= log_msg(
2945df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2946df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            reinterpret_cast<uint64_t>(cb_node->commandBuffer), __LINE__, DRAWSTATE_INVALID_PIPELINE, "DS",
294722fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis            "At Draw/Dispatch time no valid VkPipeline is bound! This is illegal. Please bind one with vkCmdBindPipeline().");
294822fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis        // Early return as any further checks below will be busted w/o a pipeline
2949cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (result) return true;
295022fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis    }
29513d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    // First check flag states
29521c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    if (VK_PIPELINE_BIND_POINT_GRAPHICS == bind_point)
295351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        result = validate_draw_state_flags(dev_data, cb_node, pPipe, indexed, msg_code);
29547a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis
29555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Now complete other state checks
295669b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis    if (VK_NULL_HANDLE != state.pipeline_layout.layout) {
295722fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis        string errorString;
295869b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis        auto pipeline_layout = pPipe->pipeline_layout;
2959169c4506062f06d6676eb4da3c9e0437d1d9d659Chris Forbes
29601c130ea631a82716dc7334de17767536525f2292Tobin Ehlis        for (const auto &set_binding_pair : pPipe->active_slots) {
29611c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            uint32_t setIndex = set_binding_pair.first;
296222fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis            // If valid set is not bound throw an error
296322fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis            if ((state.boundDescriptorSets.size() <= setIndex) || (!state.boundDescriptorSets[setIndex])) {
2964df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                result |= log_msg(
2965df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2966df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    reinterpret_cast<uint64_t>(cb_node->commandBuffer), __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_BOUND, "DS",
2967df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    "VkPipeline 0x%" PRIxLEAST64 " uses set #%u but that set is not bound.", (uint64_t)pPipe->pipeline, setIndex);
296851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            } else if (!verify_set_layout_compatibility(dev_data, state.boundDescriptorSets[setIndex], &pipeline_layout, setIndex,
296969b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                                                        errorString)) {
297069b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                // Set is bound but not compatible w/ overlapping pipeline_layout from PSO
297171511c5a10533c910bfe62c3bcf58e2a4054e7acTobin Ehlis                VkDescriptorSet setHandle = state.boundDescriptorSets[setIndex]->GetSet();
297222fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                result |=
297351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
297422fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                            (uint64_t)setHandle, __LINE__, DRAWSTATE_PIPELINE_LAYOUTS_INCOMPATIBLE, "DS",
2975414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                            "VkDescriptorSet (0x%" PRIxLEAST64
2976414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                            ") bound as set #%u is not compatible with overlapping VkPipelineLayout 0x%" PRIxLEAST64 " due to: %s",
297769b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                            reinterpret_cast<uint64_t &>(setHandle), setIndex, reinterpret_cast<uint64_t &>(pipeline_layout.layout),
297869b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                            errorString.c_str());
2979cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else {  // Valid set is bound and layout compatible, validate that it's updated
298022fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                // Pull the set node
29811c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                cvdescriptorset::DescriptorSet *descriptor_set = state.boundDescriptorSets[setIndex];
2982aa21bc3b3c5c7adfeb488fc80bdcb339d63615b8Tobin Ehlis                // Gather active bindings
2983ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                std::unordered_set<uint32_t> active_bindings;
29841c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                for (auto binding : set_binding_pair.second) {
2985ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                    active_bindings.insert(binding.first);
2986aa21bc3b3c5c7adfeb488fc80bdcb339d63615b8Tobin Ehlis                }
298722fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                // Make sure set has been updated if it has no immutable samplers
298822fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                //  If it has immutable samplers, we'll flag error later as needed depending on binding
29891c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                if (!descriptor_set->IsUpdated()) {
2990ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                    for (auto binding : active_bindings) {
29911c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                        if (!descriptor_set->GetImmutableSamplerPtrFromBinding(binding)) {
299251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                            result |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
2993cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                              VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)descriptor_set->GetSet(),
2994cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                              __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS",
2995cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                              "Descriptor Set 0x%" PRIxLEAST64
2996cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                              " bound but was never updated. It is now being used to draw so "
2997cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                              "this will result in undefined behavior.",
2998cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                              (uint64_t)descriptor_set->GetSet());
2999fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis                        }
30005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
30015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
30027433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis                // Validate the draw-time state for this descriptor set
30037433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis                std::string err_str;
30041c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                if (!descriptor_set->ValidateDrawState(set_binding_pair.second, state.dynamicOffsets[setIndex], &err_str)) {
30051c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                    auto set = descriptor_set->GetSet();
300651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                    result |= log_msg(
300751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
300851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                        reinterpret_cast<const uint64_t &>(set), __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS",
300951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                        "Descriptor set 0x%" PRIxLEAST64 " encountered the following validation error at %s() time: %s",
301051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                        reinterpret_cast<const uint64_t &>(set), function, err_str.c_str());
30117433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis                }
30125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
301322fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis        }
301422fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis    }
3015eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
3016eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    // Check general pipeline state that needs to be validated at drawtime
301751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (VK_PIPELINE_BIND_POINT_GRAPHICS == bind_point) result |= ValidatePipelineDrawtimeState(dev_data, state, cb_node, pPipe);
3018eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
30195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
30205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
30215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
302251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void UpdateDrawState(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, const VkPipelineBindPoint bind_point) {
30231c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    auto const &state = cb_state->lastBound[bind_point];
3024ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis    PIPELINE_STATE *pPipe = state.pipeline_state;
3025ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis    if (VK_NULL_HANDLE != state.pipeline_layout.layout) {
30261c130ea631a82716dc7334de17767536525f2292Tobin Ehlis        for (const auto &set_binding_pair : pPipe->active_slots) {
30271c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            uint32_t setIndex = set_binding_pair.first;
3028ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis            // Pull the set node
30291c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            cvdescriptorset::DescriptorSet *descriptor_set = state.boundDescriptorSets[setIndex];
3030ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis            // Bind this set and its active descriptor resources to the command buffer
30311c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            descriptor_set->BindCommandBuffer(cb_state, set_binding_pair.second);
30327433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis            // For given active slots record updated images & buffers
30331c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            descriptor_set->GetStorageUpdates(set_binding_pair.second, &cb_state->updateBuffers, &cb_state->updateImages);
3034ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis        }
3035ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis    }
303658b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    if (pPipe->vertexBindingDescriptions.size() > 0) {
303758b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis        cb_state->vertex_buffer_used = true;
303858b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    }
3039ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis}
3040ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis
3041a27508babf63d50aea75883a3702979193c23683Mark Young// Validate HW line width capabilities prior to setting requested line width.
3042df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinskistatic bool verifyLineWidth(layer_data *dev_data, DRAW_STATE_ERROR dsError, VkDebugReportObjectTypeEXT object_type,
3043df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            const uint64_t &target, float lineWidth) {
3044a27508babf63d50aea75883a3702979193c23683Mark Young    bool skip_call = false;
3045a27508babf63d50aea75883a3702979193c23683Mark Young
3046a27508babf63d50aea75883a3702979193c23683Mark Young    // First check to see if the physical device supports wide lines.
304751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if ((VK_FALSE == dev_data->enabled_features.wideLines) && (1.0f != lineWidth)) {
3048df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, object_type, target, __LINE__, dsError, "DS",
3049cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "Attempt to set lineWidth to %f but physical device wideLines feature "
3050cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "not supported/enabled so lineWidth must be 1.0f!",
3051a27508babf63d50aea75883a3702979193c23683Mark Young                             lineWidth);
3052a27508babf63d50aea75883a3702979193c23683Mark Young    } else {
3053a27508babf63d50aea75883a3702979193c23683Mark Young        // Otherwise, make sure the width falls in the valid range.
305451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        if ((dev_data->phys_dev_properties.properties.limits.lineWidthRange[0] > lineWidth) ||
305551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            (dev_data->phys_dev_properties.properties.limits.lineWidthRange[1] < lineWidth)) {
3056df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, object_type, target, __LINE__, dsError, "DS",
3057cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "Attempt to set lineWidth to %f but physical device limits line width "
3058cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "to between [%f, %f]!",
305951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                                 lineWidth, dev_data->phys_dev_properties.properties.limits.lineWidthRange[0],
306051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                                 dev_data->phys_dev_properties.properties.limits.lineWidthRange[1]);
3061a27508babf63d50aea75883a3702979193c23683Mark Young        }
3062a27508babf63d50aea75883a3702979193c23683Mark Young    }
3063a27508babf63d50aea75883a3702979193c23683Mark Young
3064a27508babf63d50aea75883a3702979193c23683Mark Young    return skip_call;
3065a27508babf63d50aea75883a3702979193c23683Mark Young}
3066a27508babf63d50aea75883a3702979193c23683Mark Young
30675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Verify that create state for a pipeline is valid
306851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool verifyPipelineCreateState(layer_data *dev_data, std::vector<PIPELINE_STATE *> pPipelines, int pipelineIndex) {
306983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
30705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
30714c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    PIPELINE_STATE *pPipeline = pPipelines[pipelineIndex];
30725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
30735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If create derivative bit is set, check that we've specified a base
30745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // pipeline correctly, and that the base pipeline was created to allow
30755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // derivatives.
30765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pPipeline->graphicsPipelineCI.flags & VK_PIPELINE_CREATE_DERIVATIVE_BIT) {
30774c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis        PIPELINE_STATE *pBasePipeline = nullptr;
30785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!((pPipeline->graphicsPipelineCI.basePipelineHandle != VK_NULL_HANDLE) ^
30795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis              (pPipeline->graphicsPipelineCI.basePipelineIndex != -1))) {
3080f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt            // This check is a superset of VALIDATION_ERROR_00526 and VALIDATION_ERROR_00528
3081df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip_call |=
3082df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
3083df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
3084df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        "Invalid Pipeline CreateInfo: exactly one of base pipeline index and handle must be specified");
30855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (pPipeline->graphicsPipelineCI.basePipelineIndex != -1) {
30865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (pPipeline->graphicsPipelineCI.basePipelineIndex >= pipelineIndex) {
308783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                skip_call |=
3088df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
3089df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_00518, "DS",
3090f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                            "Invalid Pipeline CreateInfo: base pipeline must occur earlier in array than derivative pipeline. %s",
3091f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                            validation_error_map[VALIDATION_ERROR_00518]);
30925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else {
30935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pBasePipeline = pPipelines[pPipeline->graphicsPipelineCI.basePipelineIndex];
30945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
30955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (pPipeline->graphicsPipelineCI.basePipelineHandle != VK_NULL_HANDLE) {
309651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            pBasePipeline = getPipelineState(dev_data, pPipeline->graphicsPipelineCI.basePipelineHandle);
30975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
30985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
30995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (pBasePipeline && !(pBasePipeline->graphicsPipelineCI.flags & VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT)) {
3100df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip_call |=
3101df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
3102df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
3103df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        "Invalid Pipeline CreateInfo: base pipeline does not allow derivatives.");
31045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
31055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
31065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
31075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pPipeline->graphicsPipelineCI.pColorBlendState != NULL) {
3108fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis        const safe_VkPipelineColorBlendStateCreateInfo *color_blend_state = pPipeline->graphicsPipelineCI.pColorBlendState;
31099a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto const render_pass_info = GetRenderPassState(dev_data, pPipeline->graphicsPipelineCI.renderPass)->createInfo.ptr();
3110fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis        const VkSubpassDescription *subpass_desc = &render_pass_info->pSubpasses[pPipeline->graphicsPipelineCI.subpass];
3111fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis        if (color_blend_state->attachmentCount != subpass_desc->colorAttachmentCount) {
3112fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis            skip_call |= log_msg(
311351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
3114fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis                reinterpret_cast<const uint64_t &>(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_02109, "DS",
3115fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis                "vkCreateGraphicsPipelines(): Render pass (0x%" PRIxLEAST64
3116fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis                ") subpass %u has colorAttachmentCount of %u which doesn't match the pColorBlendState->attachmentCount of %u. %s",
3117fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis                reinterpret_cast<const uint64_t &>(pPipeline->graphicsPipelineCI.renderPass), pPipeline->graphicsPipelineCI.subpass,
3118fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis                subpass_desc->colorAttachmentCount, color_blend_state->attachmentCount,
3119fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis                validation_error_map[VALIDATION_ERROR_02109]);
3120fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis        }
312151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        if (!dev_data->enabled_features.independentBlend) {
31223d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis            if (pPipeline->attachments.size() > 1) {
312326c548826ff0f83d12c769b51e7d6f76d1265c0eChris Forbes                VkPipelineColorBlendAttachmentState *pAttachments = &pPipeline->attachments[0];
3124c7bd67f06427b08ba65cdf2dd529c8234beebdd5Mark Lobodzinski                for (size_t i = 1; i < pPipeline->attachments.size(); i++) {
312506811df0256552cd7da9d7297672af377463fc4aMark Mueller                    // Quoting the spec: "If [the independent blend] feature is not enabled, the VkPipelineColorBlendAttachmentState
312606811df0256552cd7da9d7297672af377463fc4aMark Mueller                    // settings for all color attachments must be identical." VkPipelineColorBlendAttachmentState contains
312706811df0256552cd7da9d7297672af377463fc4aMark Mueller                    // only attachment state, so memcmp is best suited for the comparison
312806811df0256552cd7da9d7297672af377463fc4aMark Mueller                    if (memcmp(static_cast<const void *>(pAttachments), static_cast<const void *>(&pAttachments[i]),
312906811df0256552cd7da9d7297672af377463fc4aMark Mueller                               sizeof(pAttachments[0]))) {
3130df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        skip_call |=
3131df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
3132df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_01532, "DS",
3133df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    "Invalid Pipeline CreateInfo: If independent blend feature not "
3134df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    "enabled, all elements of pAttachments must be identical. %s",
3135df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    validation_error_map[VALIDATION_ERROR_01532]);
313606811df0256552cd7da9d7297672af377463fc4aMark Mueller                        break;
3137c7bd67f06427b08ba65cdf2dd529c8234beebdd5Mark Lobodzinski                    }
31385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
31395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
31405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
314151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        if (!dev_data->enabled_features.logicOp && (pPipeline->graphicsPipelineCI.pColorBlendState->logicOpEnable != VK_FALSE)) {
314283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |=
3143df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
3144df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_01533, "DS",
3145f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                        "Invalid Pipeline CreateInfo: If logic operations feature not enabled, logicOpEnable must be VK_FALSE. %s",
3146f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                        validation_error_map[VALIDATION_ERROR_01533]);
31475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
31485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
31495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3150a61b537fcb6a4f7b92cd217b3964ad7a48109da1Tobin Ehlis    // Ensure the subpass index is valid. If not, then validate_and_capture_pipeline_shader_state
31515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // produces nonsense errors that confuse users. Other layers should already
31525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // emit errors for renderpass being invalid.
31539a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto renderPass = GetRenderPassState(dev_data, pPipeline->graphicsPipelineCI.renderPass);
3154fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    if (renderPass && pPipeline->graphicsPipelineCI.subpass >= renderPass->createInfo.subpassCount) {
3155df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
3156df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                             reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_02122, "DS",
3157cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "Invalid Pipeline CreateInfo State: Subpass index %u "
3158cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "is out of range for this renderpass (0..%u). %s",
3159f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             pPipeline->graphicsPipelineCI.subpass, renderPass->createInfo.subpassCount - 1,
3160f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             validation_error_map[VALIDATION_ERROR_02122]);
31615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
31625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3163df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski    if (!GetDisables(dev_data)->shader_validation && !validate_and_capture_pipeline_shader_state(dev_data, pPipeline)) {
316483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis        skip_call = true;
31655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
316652156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes    // Each shader's stage must be unique
316752156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes    if (pPipeline->duplicate_shaders) {
316852156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes        for (uint32_t stage = VK_SHADER_STAGE_VERTEX_BIT; stage & VK_SHADER_STAGE_ALL_GRAPHICS; stage <<= 1) {
316952156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes            if (pPipeline->duplicate_shaders & stage) {
3170df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                skip_call |=
3171df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
3172df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, DRAWSTATE_INVALID_PIPELINE_CREATE_STATE,
3173df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "DS", "Invalid Pipeline CreateInfo State: Multiple shaders provided for stage %s",
3174df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            string_VkShaderStageFlagBits(VkShaderStageFlagBits(stage)));
317552156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes            }
317652156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes        }
317752156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes    }
31785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // VS is required
31795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (!(pPipeline->active_shaders & VK_SHADER_STAGE_VERTEX_BIT)) {
3180df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski        skip_call |=
3181df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
3182df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_00532, "DS",
3183df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    "Invalid Pipeline CreateInfo State: Vertex Shader required. %s", validation_error_map[VALIDATION_ERROR_00532]);
31845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
31855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Either both or neither TC/TE shaders should be defined
3186f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    if ((pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) &&
3187f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt        !(pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)) {
3188df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
3189df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                             reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_00534, "DS",
3190f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             "Invalid Pipeline CreateInfo State: TE and TC shaders must be included or excluded as a pair. %s",
3191f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             validation_error_map[VALIDATION_ERROR_00534]);
3192f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    }
3193f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    if (!(pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) &&
3194f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt        (pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)) {
3195df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
3196df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                             reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_00535, "DS",
3197f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             "Invalid Pipeline CreateInfo State: TE and TC shaders must be included or excluded as a pair. %s",
3198f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             validation_error_map[VALIDATION_ERROR_00535]);
31995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
32005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Compute shaders should be specified independent of Gfx shaders
3201f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    if (pPipeline->active_shaders & VK_SHADER_STAGE_COMPUTE_BIT) {
3202df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
3203df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                             reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_00533, "DS",
3204f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             "Invalid Pipeline CreateInfo State: Do not specify Compute Shader for Gfx Pipeline. %s",
3205f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             validation_error_map[VALIDATION_ERROR_00533]);
32065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
32075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive topology is only valid for tessellation pipelines.
32085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Mismatching primitive topology and tessellation fails graphics pipeline creation.
32095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pPipeline->active_shaders & (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) &&
3210ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        (!pPipeline->graphicsPipelineCI.pInputAssemblyState ||
3211ca546210846c65808717f8875deae39bd227c240Tobin Ehlis         pPipeline->graphicsPipelineCI.pInputAssemblyState->topology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST)) {
3212df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
3213df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                             reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_02099, "DS",
3214cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "Invalid Pipeline CreateInfo State: "
3215cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST must be set as IA "
3216cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "topology for tessellation pipelines. %s",
3217f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             validation_error_map[VALIDATION_ERROR_02099]);
32185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
3219ca546210846c65808717f8875deae39bd227c240Tobin Ehlis    if (pPipeline->graphicsPipelineCI.pInputAssemblyState &&
3220ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        pPipeline->graphicsPipelineCI.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) {
32215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (~pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) {
3222df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
3223df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                 reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_02100, "DS",
3224cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "Invalid Pipeline CreateInfo State: "
3225cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive "
3226cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "topology is only valid for tessellation pipelines. %s",
3227f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                                 validation_error_map[VALIDATION_ERROR_02100]);
32285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
32295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
3230f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt
3231f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    if (pPipeline->graphicsPipelineCI.pTessellationState &&
3232f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt        ((pPipeline->graphicsPipelineCI.pTessellationState->patchControlPoints == 0) ||
3233f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt         (pPipeline->graphicsPipelineCI.pTessellationState->patchControlPoints >
323451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis          dev_data->phys_dev_properties.properties.limits.maxTessellationPatchSize))) {
3235df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
3236df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                             reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_01426, "DS",
3237cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "Invalid Pipeline CreateInfo State: "
3238cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive "
3239cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "topology used with patchControlPoints value %u."
3240cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             " patchControlPoints should be >0 and <=%u. %s",
3241f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             pPipeline->graphicsPipelineCI.pTessellationState->patchControlPoints,
324251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                             dev_data->phys_dev_properties.properties.limits.maxTessellationPatchSize,
3243f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                             validation_error_map[VALIDATION_ERROR_01426]);
3244f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    }
3245f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt
32466b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen    // If a rasterization state is provided...
3247a27508babf63d50aea75883a3702979193c23683Mark Young    if (pPipeline->graphicsPipelineCI.pRasterizationState) {
32486b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen        // Make sure that the line width conforms to the HW.
3249a27508babf63d50aea75883a3702979193c23683Mark Young        if (!isDynamic(pPipeline, VK_DYNAMIC_STATE_LINE_WIDTH)) {
3250df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip_call |=
3251df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                verifyLineWidth(dev_data, DRAWSTATE_INVALID_PIPELINE_CREATE_STATE,
3252df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT, reinterpret_cast<uint64_t const &>(pPipeline->pipeline),
3253df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                pPipeline->graphicsPipelineCI.pRasterizationState->lineWidth);
3254a27508babf63d50aea75883a3702979193c23683Mark Young        }
32555dcdd90e54199dfeb29938a3a03d998397c22664Chris Forbes
325658c5552c73679f81f57a64a809f7d4d6d52f4ce3Mark Lobodzinski        if ((pPipeline->graphicsPipelineCI.pRasterizationState->depthClampEnable == VK_TRUE) &&
325758c5552c73679f81f57a64a809f7d4d6d52f4ce3Mark Lobodzinski            (!dev_data->enabled_features.depthClamp)) {
3258df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
3259df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                 reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_01455, "DS",
326058c5552c73679f81f57a64a809f7d4d6d52f4ce3Mark Lobodzinski                                 "vkCreateGraphicsPipelines(): the depthClamp device feature is disabled: the depthClampEnable "
326158c5552c73679f81f57a64a809f7d4d6d52f4ce3Mark Lobodzinski                                 "member of the VkPipelineRasterizationStateCreateInfo structure must be set to VK_FALSE. %s",
326258c5552c73679f81f57a64a809f7d4d6d52f4ce3Mark Lobodzinski                                 validation_error_map[VALIDATION_ERROR_01455]);
326358c5552c73679f81f57a64a809f7d4d6d52f4ce3Mark Lobodzinski        }
326458c5552c73679f81f57a64a809f7d4d6d52f4ce3Mark Lobodzinski
3265434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski        if (!isDynamic(pPipeline, VK_DYNAMIC_STATE_DEPTH_BIAS) &&
3266434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski            (pPipeline->graphicsPipelineCI.pRasterizationState->depthBiasClamp != 0.0) &&
3267434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski            (!dev_data->enabled_features.depthBiasClamp)) {
3268df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
3269df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                 reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, DRAWSTATE_INVALID_FEATURE, "DS",
3270434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski                                 "vkCreateGraphicsPipelines(): the depthBiasClamp device feature is disabled: the depthBiasClamp "
3271434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski                                 "member of the VkPipelineRasterizationStateCreateInfo structure must be set to 0.0 unless the "
3272434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski                                 "VK_DYNAMIC_STATE_DEPTH_BIAS dynamic state is enabled");
3273434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski        }
3274434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski
32756b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen        // If rasterization is enabled...
32766b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen        if (pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable == VK_FALSE) {
32776b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen            auto subpass_desc = renderPass ? &renderPass->createInfo.pSubpasses[pPipeline->graphicsPipelineCI.subpass] : nullptr;
32786b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen
3279148e8028deee2b4b00ccd4a69210897add328265Mark Lobodzinski            if ((pPipeline->graphicsPipelineCI.pMultisampleState->alphaToOneEnable == VK_TRUE) &&
3280148e8028deee2b4b00ccd4a69210897add328265Mark Lobodzinski                (!dev_data->enabled_features.alphaToOne)) {
3281df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
3282df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                     reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_01464, "DS",
3283148e8028deee2b4b00ccd4a69210897add328265Mark Lobodzinski                                     "vkCreateGraphicsPipelines(): the alphaToOne device feature is disabled: the alphaToOneEnable "
32844c1f7e564e7a3f705ac142b1519c48a83a513b58Mark Lobodzinski                                     "member of the VkPipelineMultisampleStateCreateInfo structure must be set to VK_FALSE. %s",
3285148e8028deee2b4b00ccd4a69210897add328265Mark Lobodzinski                                     validation_error_map[VALIDATION_ERROR_01464]);
3286148e8028deee2b4b00ccd4a69210897add328265Mark Lobodzinski            }
3287148e8028deee2b4b00ccd4a69210897add328265Mark Lobodzinski
32886b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen            // If subpass uses a depth/stencil attachment, pDepthStencilState must be a pointer to a valid structure
32896b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen            if (subpass_desc && subpass_desc->pDepthStencilAttachment &&
32906b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen                subpass_desc->pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
32916b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen                if (!pPipeline->graphicsPipelineCI.pDepthStencilState) {
3292df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    skip_call |=
3293df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
3294df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_02115, "DS",
3295df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                "Invalid Pipeline CreateInfo State: pDepthStencilState is NULL when rasterization is "
3296df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                "enabled and subpass uses a depth/stencil attachment. %s",
3297df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                validation_error_map[VALIDATION_ERROR_02115]);
32989580629edfc5154cc9e36974cca12966fbd748b9Mark Lobodzinski
32999580629edfc5154cc9e36974cca12966fbd748b9Mark Lobodzinski                } else if ((pPipeline->graphicsPipelineCI.pDepthStencilState->depthBoundsTestEnable == VK_TRUE) &&
33009580629edfc5154cc9e36974cca12966fbd748b9Mark Lobodzinski                           (!dev_data->enabled_features.depthBounds)) {
33019580629edfc5154cc9e36974cca12966fbd748b9Mark Lobodzinski                    skip_call |= log_msg(
3302df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
3303df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, DRAWSTATE_INVALID_FEATURE, "DS",
33049580629edfc5154cc9e36974cca12966fbd748b9Mark Lobodzinski                        "vkCreateGraphicsPipelines(): the depthBounds device feature is disabled: the depthBoundsTestEnable "
33059580629edfc5154cc9e36974cca12966fbd748b9Mark Lobodzinski                        "member of the VkPipelineDepthStencilStateCreateInfo structure must be set to VK_FALSE.");
33066b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen                }
33075dcdd90e54199dfeb29938a3a03d998397c22664Chris Forbes            }
3308326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen
3309326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen            // If subpass uses color attachments, pColorBlendState must be valid pointer
3310326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen            if (subpass_desc) {
3311326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                uint32_t color_attachment_count = 0;
3312326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                for (uint32_t i = 0; i < subpass_desc->colorAttachmentCount; ++i) {
3313326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                    if (subpass_desc->pColorAttachments[i].attachment != VK_ATTACHMENT_UNUSED) {
3314326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                        ++color_attachment_count;
3315326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                    }
3316326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                }
3317326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                if (color_attachment_count > 0 && pPipeline->graphicsPipelineCI.pColorBlendState == nullptr) {
3318df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    skip_call |=
3319df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
3320df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                reinterpret_cast<uint64_t &>(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_02116, "DS",
3321df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                "Invalid Pipeline CreateInfo State: pColorBlendState is NULL when rasterization is "
3322df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                "enabled and subpass uses color attachments. %s",
3323df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                validation_error_map[VALIDATION_ERROR_02116]);
3324326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                }
3325326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen            }
33265dcdd90e54199dfeb29938a3a03d998397c22664Chris Forbes        }
33275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
33286b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen
332983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
33305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
33315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
33325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Free the Pipeline nodes
333351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void deletePipelines(layer_data *dev_data) {
333451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (dev_data->pipelineMap.size() <= 0) return;
333551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    for (auto &pipe_map_pair : dev_data->pipelineMap) {
3336ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        delete pipe_map_pair.second;
33375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
333851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    dev_data->pipelineMap.clear();
33395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
33405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
33415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Block of code at start here specifically for managing/tracking DSs
33425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
33435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Return Pool node ptr for specified pool or else NULL
33449a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisDESCRIPTOR_POOL_STATE *GetDescriptorPoolState(const layer_data *dev_data, const VkDescriptorPool pool) {
3345bb7ea477706f90eb2a72887f652795bc79f60ddeTobin Ehlis    auto pool_it = dev_data->descriptorPoolMap.find(pool);
3346bb7ea477706f90eb2a72887f652795bc79f60ddeTobin Ehlis    if (pool_it == dev_data->descriptorPoolMap.end()) {
33475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return NULL;
33485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
3349bb7ea477706f90eb2a72887f652795bc79f60ddeTobin Ehlis    return pool_it->second;
33505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
33515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
33525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Validate that given set is valid and that it's not being used by an in-flight CmdBuffer
33535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// func_str is the name of the calling function
3354e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves// Return false if no errors occur
3355e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves// Return true if validation error occurs and callback returns true (to skip upcoming API call down the chain)
33560dcd0f7b37456e2e552d37094ba503c0d089b906Tobin Ehlisstatic bool validateIdleDescriptorSet(const layer_data *dev_data, VkDescriptorSet set, std::string func_str) {
3357cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.idle_descriptor_set) return false;
3358e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
33590dcd0f7b37456e2e552d37094ba503c0d089b906Tobin Ehlis    auto set_node = dev_data->setMap.find(set);
33600dcd0f7b37456e2e552d37094ba503c0d089b906Tobin Ehlis    if (set_node == dev_data->setMap.end()) {
33610dcd0f7b37456e2e552d37094ba503c0d089b906Tobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
33625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                             (uint64_t)(set), __LINE__, DRAWSTATE_DOUBLE_DESTROY, "DS",
3363414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                             "Cannot call %s() on descriptor set 0x%" PRIxLEAST64 " that has not been allocated.", func_str.c_str(),
33645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                             (uint64_t)(set));
33655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
33661c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis        // TODO : This covers various error cases so should pass error enum into this function and use passed in enum here
33675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (set_node->second->in_use.load()) {
33681c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis            skip_call |=
33690dcd0f7b37456e2e552d37094ba503c0d089b906Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
33701c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis                        (uint64_t)(set), __LINE__, VALIDATION_ERROR_00919, "DS",
33711c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis                        "Cannot call %s() on descriptor set 0x%" PRIxLEAST64 " that is in use by a command buffer. %s",
33721c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis                        func_str.c_str(), (uint64_t)(set), validation_error_map[VALIDATION_ERROR_00919]);
33735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
33745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
33755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
33765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
3377f80bf38f4fb3f177b3e1be11b7b1c5edcdbf7d9bChris Forbes
3378e6651096ed8f07840447783c66827cc16d659a49Tobin Ehlis// Remove set from setMap and delete the set
33799dd448578d59cb5ce692e833ba230783b30f3550Tobin Ehlisstatic void freeDescriptorSet(layer_data *dev_data, cvdescriptorset::DescriptorSet *descriptor_set) {
33809dd448578d59cb5ce692e833ba230783b30f3550Tobin Ehlis    dev_data->setMap.erase(descriptor_set->GetSet());
33819dd448578d59cb5ce692e833ba230783b30f3550Tobin Ehlis    delete descriptor_set;
33829dd448578d59cb5ce692e833ba230783b30f3550Tobin Ehlis}
33835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Free all DS Pools including their Sets & related sub-structs
33845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// NOTE : Calls to this function should be wrapped in mutex
338551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void deletePools(layer_data *dev_data) {
338651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (dev_data->descriptorPoolMap.size() <= 0) return;
338751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    for (auto ii = dev_data->descriptorPoolMap.begin(); ii != dev_data->descriptorPoolMap.end(); ++ii) {
3388c5f47f0a54e14c47d402aeabc6498d981ecda9ccTobin Ehlis        // Remove this pools' sets from setMap and delete them
3389cb9ce9e05b8e939d3da35c64997c70049877f4feTobin Ehlis        for (auto ds : (*ii).second->sets) {
339051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            freeDescriptorSet(dev_data, ds);
33915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
3392f13bee0887f3c3d1d597c82869864be3be836737Tobin Ehlis        (*ii).second->sets.clear();
33935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
339451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    dev_data->descriptorPoolMap.clear();
33955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
33965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
339751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void clearDescriptorPool(layer_data *dev_data, const VkDevice device, const VkDescriptorPool pool,
33985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                VkDescriptorPoolResetFlags flags) {
33999a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DESCRIPTOR_POOL_STATE *pPool = GetDescriptorPoolState(dev_data, pool);
3400de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    // TODO: validate flags
3401de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    // For every set off of this pool, clear it, remove from setMap, and free cvdescriptorset::DescriptorSet
3402de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    for (auto ds : pPool->sets) {
340351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        freeDescriptorSet(dev_data, ds);
3404de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    }
3405de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    pPool->sets.clear();
3406de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    // Reset available count for each type and available sets for this pool
3407de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    for (uint32_t i = 0; i < pPool->availableDescriptorTypeCount.size(); ++i) {
3408de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis        pPool->availableDescriptorTypeCount[i] = pPool->maxDescriptorTypeCount[i];
34095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
3410de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    pPool->availableSets = pPool->maxSets;
34115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
34125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
34135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// For given CB object, fetch associated CB Node from map
34149a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisGLOBAL_CB_NODE *GetCBNode(layer_data const *dev_data, const VkCommandBuffer cb) {
341551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->commandBufferMap.find(cb);
341651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->commandBufferMap.end()) {
34175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return NULL;
34185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
34195121a8dcacb23766ba4455b4eea429f0a3d62099Chris Forbes    return it->second;
34205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
34215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Free all CB Nodes
34225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// NOTE : Calls to this function should be wrapped in mutex
342351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void deleteCommandBuffers(layer_data *dev_data) {
342451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (dev_data->commandBufferMap.empty()) {
34255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return;
34265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
342751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    for (auto ii = dev_data->commandBufferMap.begin(); ii != dev_data->commandBufferMap.end(); ++ii) {
34285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        delete (*ii).second;
34295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
343051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    dev_data->commandBufferMap.clear();
34315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
34325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
343329f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis// If a renderpass is active, verify that the given command type is appropriate for current subpass state
343429f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlisbool ValidateCmdSubpassState(const layer_data *dev_data, const GLOBAL_CB_NODE *pCB, const CMD_TYPE cmd_type) {
3435cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!pCB->activeRenderPass) return false;
3436e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
3437d0d8e333806eaac08bdc87ddeff886dc2b0f09e7Tobin Ehlis    if (pCB->activeSubpassContents == VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS &&
3438d0d8e333806eaac08bdc87ddeff886dc2b0f09e7Tobin Ehlis        (cmd_type != CMD_EXECUTECOMMANDS && cmd_type != CMD_NEXTSUBPASS && cmd_type != CMD_ENDRENDERPASS)) {
3439df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3440df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                             reinterpret_cast<uint64_t>(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
34415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                             "Commands cannot be called in a subpass using secondary command buffers.");
34425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else if (pCB->activeSubpassContents == VK_SUBPASS_CONTENTS_INLINE && cmd_type == CMD_EXECUTECOMMANDS) {
3443df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3444df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                             reinterpret_cast<uint64_t>(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
34455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                             "vkCmdExecuteCommands() cannot be called in a subpass using inline commands.");
34465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
34475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
34485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
34495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3450baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardtbool ValidateCmdQueueFlags(layer_data *dev_data, GLOBAL_CB_NODE *cb_node, const char *caller_name, VkQueueFlags required_flags,
3451baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                           UNIQUE_VALIDATION_ERROR_CODE error_code) {
3452baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    auto pool = GetCommandPoolNode(dev_data, cb_node->createInfo.commandPool);
3453baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    if (pool) {
3454baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        VkQueueFlags queue_flags = dev_data->phys_dev_properties.queue_family_properties[pool->queueFamilyIndex].queueFlags;
3455baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        if (!(required_flags & queue_flags)) {
3456baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt            string required_flags_string;
3457baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt            for (auto flag : {VK_QUEUE_TRANSFER_BIT, VK_QUEUE_GRAPHICS_BIT, VK_QUEUE_COMPUTE_BIT}) {
3458baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                if (flag & required_flags) {
3459baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                    if (required_flags_string.size()) {
3460baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                        required_flags_string += " or ";
3461baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                    }
3462baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                    required_flags_string += string_VkQueueFlagBits(flag);
3463baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                }
3464baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt            }
3465baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt            return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3466baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                           reinterpret_cast<uint64_t>(cb_node->commandBuffer), __LINE__, error_code, "DS",
3467baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                           "Cannot call %s on a command buffer allocated from a pool without %s capabilities. %s.", caller_name,
3468baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                           required_flags_string.c_str(), validation_error_map[error_code]);
3469baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        }
3470baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    }
34715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return false;
34725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
34735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3474ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinskistatic bool ReportInvalidCommandBuffer(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, const char *call_source) {
3475ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski    bool skip = false;
3476ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski    for (auto obj : cb_state->broken_bindings) {
3477ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        const char *type_str = object_type_to_string(obj.type);
3478ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        // Descriptor sets are a special case that can be either destroyed or updated to invalidate a CB
3479ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        const char *cause_str = (obj.type == VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT) ? "destroyed or updated" : "destroyed";
3480ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3481ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                        reinterpret_cast<uint64_t &>(cb_state->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
3482ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                        "You are adding %s to command buffer 0x%p that is invalid because bound %s 0x%" PRIxLEAST64 " was %s.",
3483ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                        call_source, cb_state->commandBuffer, type_str, obj.handle, cause_str);
3484ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski    }
3485ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski    return skip;
3486ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski}
3487ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski
3488623784ad78c8b77a78c4db613db974c12e5f5a43Mark Lobodzinski// Validate the given command being added to the specified cmd buffer, flagging errors if CB is not in the recording state or if
3489623784ad78c8b77a78c4db613db974c12e5f5a43Mark Lobodzinski// there's an issue with the Cmd ordering
3490946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinskibool ValidateCmd(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, const CMD_TYPE cmd, const char *caller_name) {
3491946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
3492946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (cb_state->state != CB_RECORDING) {
3493946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        if (cb_state->state == CB_INVALID) {
3494946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            skip |= ReportInvalidCommandBuffer(dev_data, cb_state, caller_name);
3495ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        } else {
3496946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3497946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            reinterpret_cast<uint64_t &>(cb_state->commandBuffer), __LINE__, DRAWSTATE_NO_BEGIN_COMMAND_BUFFER,
3498946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            "DS", "You must call vkBeginCommandBuffer() before this call to %s", caller_name);
3499ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        }
35007651c2eb9fe152ba62921ed60454afd882357e2aTobin Ehlis    } else {
3501946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmdSubpassState(dev_data, cb_state, cmd);
35025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
3503946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    return skip;
35045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
350529f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis
35061ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlisvoid UpdateCmdBufferLastCmd(GLOBAL_CB_NODE *cb_state, const CMD_TYPE cmd) {
350729f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis    if (cb_state->state == CB_RECORDING) {
350829f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        cb_state->last_cmd = cmd;
350929f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis    }
351029f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis}
35117e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis// For given object struct return a ptr of BASE_NODE type for its wrapping struct
35127e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin EhlisBASE_NODE *GetStateStructPtrFromObject(layer_data *dev_data, VK_OBJECT object_struct) {
35137e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    BASE_NODE *base_ptr = nullptr;
35147e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    switch (object_struct.type) {
3515cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT: {
35169a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetSetNode(dev_data, reinterpret_cast<VkDescriptorSet &>(object_struct.handle));
3517cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3518cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3519cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT: {
35209a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetSamplerState(dev_data, reinterpret_cast<VkSampler &>(object_struct.handle));
3521cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3522cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3523cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT: {
35249a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetQueryPoolNode(dev_data, reinterpret_cast<VkQueryPool &>(object_struct.handle));
3525cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3526cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3527cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT: {
3528cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            base_ptr = getPipelineState(dev_data, reinterpret_cast<VkPipeline &>(object_struct.handle));
3529cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3530cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3531cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT: {
35329a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetBufferState(dev_data, reinterpret_cast<VkBuffer &>(object_struct.handle));
3533cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3534cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3535cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT: {
35369a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetBufferViewState(dev_data, reinterpret_cast<VkBufferView &>(object_struct.handle));
3537cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3538cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3539cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT: {
35409a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetImageState(dev_data, reinterpret_cast<VkImage &>(object_struct.handle));
3541cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3542cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3543cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT: {
35449a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetImageViewState(dev_data, reinterpret_cast<VkImageView &>(object_struct.handle));
3545cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3546cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3547cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT: {
35489a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetEventNode(dev_data, reinterpret_cast<VkEvent &>(object_struct.handle));
3549cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3550cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3551cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT: {
35529a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetDescriptorPoolState(dev_data, reinterpret_cast<VkDescriptorPool &>(object_struct.handle));
3553cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3554cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3555cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT: {
35569a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetCommandPoolNode(dev_data, reinterpret_cast<VkCommandPool &>(object_struct.handle));
3557cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3558cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3559cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT: {
35609a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetFramebufferState(dev_data, reinterpret_cast<VkFramebuffer &>(object_struct.handle));
3561cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3562cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3563cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT: {
35649a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetRenderPassState(dev_data, reinterpret_cast<VkRenderPass &>(object_struct.handle));
3565cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3566cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3567cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT: {
35689a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetMemObjInfo(dev_data, reinterpret_cast<VkDeviceMemory &>(object_struct.handle));
3569cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3570cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3571cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
3572cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // TODO : Any other objects to be handled here?
3573cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            assert(0);
3574cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3575bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis    }
35767e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    return base_ptr;
35777e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis}
35787e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis
35797e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis// Tie the VK_OBJECT to the cmd buffer which includes:
35807e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis//  Add object_binding to cmd buffer
35817e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis//  Add cb_binding to object
35827e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlisstatic void addCommandBufferBinding(std::unordered_set<GLOBAL_CB_NODE *> *cb_bindings, VK_OBJECT obj, GLOBAL_CB_NODE *cb_node) {
35837e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    cb_bindings->insert(cb_node);
35847e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    cb_node->object_bindings.insert(obj);
35857e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis}
35867e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis// For a given object, if cb_node is in that objects cb_bindings, remove cb_node
35877e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlisstatic void removeCommandBufferBinding(layer_data *dev_data, VK_OBJECT const *object, GLOBAL_CB_NODE *cb_node) {
35887e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    BASE_NODE *base_obj = GetStateStructPtrFromObject(dev_data, *object);
3589cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (base_obj) base_obj->cb_bindings.erase(cb_node);
3590bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis}
35915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Reset the command buffer state
35925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Maintain the createInfo and set state to CB_NEW, but clear all other state
3593400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlisstatic void resetCB(layer_data *dev_data, const VkCommandBuffer cb) {
3594400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis    GLOBAL_CB_NODE *pCB = dev_data->commandBufferMap[cb];
35955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
3596b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine        pCB->in_use.store(0);
3597347d4d3139a1e743ed85bd375c20fd35bbe68d74Chris Forbes        pCB->last_cmd = CMD_NONE;
35985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Reset CB state (note that createInfo is not cleared)
35995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->commandBuffer = cb;
36005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        memset(&pCB->beginInfo, 0, sizeof(VkCommandBufferBeginInfo));
36015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        memset(&pCB->inheritanceInfo, 0, sizeof(VkCommandBufferInheritanceInfo));
36025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->numCmds = 0;
36035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        memset(pCB->drawCount, 0, NUM_DRAW_TYPES * sizeof(uint64_t));
36045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->state = CB_NEW;
36055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->submitCount = 0;
36065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status = 0;
3607b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes        pCB->viewportMask = 0;
3608b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes        pCB->scissorMask = 0;
360993c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski
361072d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis        for (uint32_t i = 0; i < VK_PIPELINE_BIND_POINT_RANGE_SIZE; ++i) {
361172d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis            pCB->lastBound[i].reset();
361272d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis        }
361393c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski
36145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        memset(&pCB->activeRenderPassBeginInfo, 0, sizeof(pCB->activeRenderPassBeginInfo));
3615ee691f5c5fa87aac3750454d2bca2cb582e4e817Chris Forbes        pCB->activeRenderPass = nullptr;
36165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->activeSubpassContents = VK_SUBPASS_CONTENTS_INLINE;
36175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->activeSubpass = 0;
3618e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis        pCB->broken_bindings.clear();
36195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->waitedEvents.clear();
36205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->events.clear();
3621c7e6bc41aa9c6e5a677b138b9459b252cd3bedf2Mark Lobodzinski        pCB->writeEventsBeforeWait.clear();
36225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->waitedEventsBeforeQueryReset.clear();
36235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->queryToStateMap.clear();
36245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->activeQueries.clear();
36255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->startedQueries.clear();
3626abfafae4ec5d76e520916b03d196e474e972c949Michael Lentine        pCB->imageSubresourceMap.clear();
36275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->imageLayoutMap.clear();
36285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->eventToStageMap.clear();
36295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->drawData.clear();
36305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->currentDrawData.buffers.clear();
363158b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis        pCB->vertex_buffer_used = false;
36325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->primaryCommandBuffer = VK_NULL_HANDLE;
3633bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        // Make sure any secondaryCommandBuffers are removed from globalInFlight
3634bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        for (auto secondary_cb : pCB->secondaryCommandBuffers) {
3635bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis            dev_data->globalInFlightCmdBuffers.erase(secondary_cb);
3636bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        }
36375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->secondaryCommandBuffers.clear();
36387a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        pCB->updateImages.clear();
36397a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        pCB->updateBuffers.clear();
3640400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis        clear_cmd_buf_and_mem_references(dev_data, pCB);
3641b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        pCB->eventUpdates.clear();
3642d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        pCB->queryUpdates.clear();
364393c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski
3644bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis        // Remove object bindings
3645bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis        for (auto obj : pCB->object_bindings) {
3646bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis            removeCommandBufferBinding(dev_data, &obj, pCB);
3647bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis        }
3648a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis        pCB->object_bindings.clear();
364993c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski        // Remove this cmdBuffer's reference from each FrameBuffer's CB ref list
365093c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski        for (auto framebuffer : pCB->framebuffers) {
36519a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto fb_state = GetFramebufferState(dev_data, framebuffer);
3652cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (fb_state) fb_state->cb_bindings.erase(pCB);
365393c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski        }
365493c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski        pCB->framebuffers.clear();
36557003b38da5cc27a063af3c45080f3a35438283eeTobin Ehlis        pCB->activeFramebuffer = VK_NULL_HANDLE;
36565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
36575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
36585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
36595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Set PSO-related status bits for CB, including dynamic state set via PSO
36604c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic void set_cb_pso_status(GLOBAL_CB_NODE *pCB, const PIPELINE_STATE *pPipe) {
36615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Account for any dynamic state not set via this PSO
3662ca546210846c65808717f8875deae39bd227c240Tobin Ehlis    if (!pPipe->graphicsPipelineCI.pDynamicState ||
3663cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        !pPipe->graphicsPipelineCI.pDynamicState->dynamicStateCount) {  // All state is static
36644052946ae557337ff95f3725e879131b1c63f865Tobin Ehlis        pCB->status |= CBSTATUS_ALL_STATE_SET;
36655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
36665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // First consider all state on
36675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Then unset any state that's noted as dynamic in PSO
36685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Finally OR that into CB statemask
36694052946ae557337ff95f3725e879131b1c63f865Tobin Ehlis        CBStatusFlags psoDynStateMask = CBSTATUS_ALL_STATE_SET;
3670ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        for (uint32_t i = 0; i < pPipe->graphicsPipelineCI.pDynamicState->dynamicStateCount; i++) {
3671ca546210846c65808717f8875deae39bd227c240Tobin Ehlis            switch (pPipe->graphicsPipelineCI.pDynamicState->pDynamicStates[i]) {
3672cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_LINE_WIDTH:
3673cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_LINE_WIDTH_SET;
3674cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3675cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_DEPTH_BIAS:
3676cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_DEPTH_BIAS_SET;
3677cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3678cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_BLEND_CONSTANTS:
3679cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_BLEND_CONSTANTS_SET;
3680cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3681cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_DEPTH_BOUNDS:
3682cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_DEPTH_BOUNDS_SET;
3683cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3684cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK:
3685cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_STENCIL_READ_MASK_SET;
3686cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3687cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_STENCIL_WRITE_MASK:
3688cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_STENCIL_WRITE_MASK_SET;
3689cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3690cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_STENCIL_REFERENCE:
3691cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_STENCIL_REFERENCE_SET;
3692cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3693cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                default:
3694cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    // TODO : Flag error here
3695cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
36965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
36975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
36985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= psoDynStateMask;
36995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
37005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
37015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3702623784ad78c8b77a78c4db613db974c12e5f5a43Mark Lobodzinski// Flags validation error if the associated call is made inside a render pass. The apiName routine should ONLY be called outside a
3703623784ad78c8b77a78c4db613db974c12e5f5a43Mark Lobodzinski// render pass.
370451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisbool insideRenderPass(const layer_data *dev_data, GLOBAL_CB_NODE *pCB, const char *apiName, UNIQUE_VALIDATION_ERROR_CODE msgCode) {
3705e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool inside = false;
37065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB->activeRenderPass) {
370751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        inside = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3708ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                         (uint64_t)pCB->commandBuffer, __LINE__, msgCode, "DS",
3709ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                         "%s: It is invalid to issue this call inside an active render pass (0x%" PRIxLEAST64 "). %s", apiName,
3710ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                         (uint64_t)pCB->activeRenderPass->renderPass, validation_error_map[msgCode]);
37115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
37125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return inside;
37135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
37145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
37155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Flags validation error if the associated call is made outside a render pass. The apiName
37165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// routine should ONLY be called inside a render pass.
371751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisbool outsideRenderPass(const layer_data *dev_data, GLOBAL_CB_NODE *pCB, const char *apiName, UNIQUE_VALIDATION_ERROR_CODE msgCode) {
3718e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool outside = false;
37195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (((pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_PRIMARY) && (!pCB->activeRenderPass)) ||
37205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        ((pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY) && (!pCB->activeRenderPass) &&
37215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis         !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT))) {
372251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        outside = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3723ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                          (uint64_t)pCB->commandBuffer, __LINE__, msgCode, "DS",
3724ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                          "%s: This call must be issued inside an active render pass. %s", apiName, validation_error_map[msgCode]);
37255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
37265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return outside;
37275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
37285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3729f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbesstatic void init_core_validation(instance_layer_data *instance_data, const VkAllocationCallbacks *pAllocator) {
3730b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis    layer_debug_actions(instance_data->report_data, instance_data->logging_callback, pAllocator, "lunarg_core_validation");
37315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
37325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3733747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbesstatic void checkInstanceRegisterExtensions(const VkInstanceCreateInfo *pCreateInfo, instance_layer_data *instance_data) {
3734747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
3735747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_SURFACE_EXTENSION_NAME))
3736747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->surfaceExtensionEnabled = true;
3737747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_DISPLAY_EXTENSION_NAME))
3738747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->displayExtensionEnabled = true;
3739747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_ANDROID_KHR
3740747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_ANDROID_SURFACE_EXTENSION_NAME))
3741747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->androidSurfaceExtensionEnabled = true;
3742747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#endif
3743747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_MIR_KHR
3744747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_MIR_SURFACE_EXTENSION_NAME))
3745747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->mirSurfaceExtensionEnabled = true;
3746747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#endif
3747747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WAYLAND_KHR
3748747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME))
3749747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->waylandSurfaceExtensionEnabled = true;
3750747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#endif
3751747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WIN32_KHR
3752747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_WIN32_SURFACE_EXTENSION_NAME))
3753747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->win32SurfaceExtensionEnabled = true;
3754747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#endif
3755747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XCB_KHR
3756747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_XCB_SURFACE_EXTENSION_NAME))
3757747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->xcbSurfaceExtensionEnabled = true;
3758747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#endif
3759747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XLIB_KHR
3760747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_XLIB_SURFACE_EXTENSION_NAME))
3761747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            instance_data->xlibSurfaceExtensionEnabled = true;
3762747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#endif
3763747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
3764747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
3765747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
37667a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis// For the given ValidationCheck enum, set all relevant instance disabled flags to true
37677a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlisvoid SetDisabledFlags(instance_layer_data *instance_data, VkValidationFlagsEXT *val_flags_struct) {
37687a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    for (uint32_t i = 0; i < val_flags_struct->disabledValidationCheckCount; ++i) {
37697a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis        switch (val_flags_struct->pDisabledValidationChecks[i]) {
37707a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis            case VK_VALIDATION_CHECK_ALL_EXT:
37717a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis                // Set all disabled flags to true
37727a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis                instance_data->disabled.SetAll(true);
37737a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis                break;
37747a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis            default:
37757a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis                break;
37767a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis        }
37777a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    }
37787a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis}
37797a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis
3780bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
3781bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              VkInstance *pInstance) {
37825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkLayerInstanceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
37835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
37845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(chain_info->u.pLayerInfo);
37855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
37865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance");
3787cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (fpCreateInstance == NULL) return VK_ERROR_INITIALIZATION_FAILED;
37885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
37895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Advance the link info for the next element on the chain
37905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
37915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
37925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
3793cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (result != VK_SUCCESS) return result;
37945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
379556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(*pInstance), instance_layer_data_map);
379656a5ba3e60a723781945959ffc10e2e215350de5Chia-I Wu    instance_data->instance = *pInstance;
37979172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    layer_init_instance_dispatch_table(*pInstance, &instance_data->dispatch_table, fpGetInstanceProcAddr);
37989172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    instance_data->report_data = debug_report_create_instance(
37999172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes        &instance_data->dispatch_table, *pInstance, pCreateInfo->enabledExtensionCount, pCreateInfo->ppEnabledExtensionNames);
3800747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    checkInstanceRegisterExtensions(pCreateInfo, instance_data);
3801b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis    init_core_validation(instance_data, pAllocator);
3802825ac70f99460ccb9494d34f93d8ee7ec303e5deMark Lobodzinski
38035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    ValidateLayerOrdering(*pCreateInfo);
38047a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    // Parse any pNext chains
38057a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    if (pCreateInfo->pNext) {
38067a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis        GENERIC_HEADER *struct_header = (GENERIC_HEADER *)pCreateInfo->pNext;
38077a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis        while (struct_header) {
38087a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis            // Check for VkValidationFlagsExt
38097a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis            if (VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT == struct_header->sType) {
38107a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis                SetDisabledFlags(instance_data, (VkValidationFlagsEXT *)struct_header);
38117a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis            }
38127a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis            struct_header = (GENERIC_HEADER *)struct_header->pNext;
38137a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis        }
38147a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    }
38155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
38165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
38175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
38185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
381925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// Hook DestroyInstance to remove tableInstanceMap entry
382089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL DestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
38215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODOSC : Shouldn't need any customization here
38225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dispatch_key key = get_dispatch_key(instance);
38235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TBD: Need any locking this early, in case this function is called at the
38245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // same time by more than one thread?
382556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(key, instance_layer_data_map);
38269172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    instance_data->dispatch_table.DestroyInstance(instance, pAllocator);
38275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3828b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::lock_guard<std::mutex> lock(global_lock);
38295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Clean up logging callback, if any
38309172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    while (instance_data->logging_callback.size() > 0) {
38319172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes        VkDebugReportCallbackEXT callback = instance_data->logging_callback.back();
38329172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes        layer_destroy_msg_callback(instance_data->report_data, callback, pAllocator);
38339172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes        instance_data->logging_callback.pop_back();
38345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
38355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
38369172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    layer_debug_report_destroy_instance(instance_data->report_data);
38375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_data_map.erase(key);
38385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
38395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3840373469f006399d6b5204ee05db3b56beb168b36fMark Youngstatic void checkDeviceRegisterExtensions(const VkDeviceCreateInfo *pCreateInfo, VkDevice device) {
38415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t i;
3842bee1d36c54af112766d4e8552ad302f39290683aMark Lobodzinski    // TBD: Need any locking, in case this function is called at the same time by more than one thread?
384356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
38445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->device_extensions.wsi_enabled = false;
3845c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young    dev_data->device_extensions.wsi_display_swapchain_enabled = false;
3846bee1d36c54af112766d4e8552ad302f39290683aMark Lobodzinski    dev_data->device_extensions.nv_glsl_shader_enabled = false;
38476246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    dev_data->device_extensions.khr_descriptor_update_template_enabled = false;
384881b2d76c449bb91569776e2b8e68130f509d53bcChris Forbes    dev_data->device_extensions.khr_shader_draw_parameters_enabled = false;
38490e2296e24065d02615ee87561bbb80af414a1ddfMike Schuchardt    dev_data->device_extensions.khr_maintenance1_enabled = false;
38502664122d97c3f0a98b3e5d12833bbb20196ca837Mark Lobodzinski    dev_data->device_extensions.nv_geometry_shader_passthrough_enabled = false;
38515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
38525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
3853bee1d36c54af112766d4e8552ad302f39290683aMark Lobodzinski        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0) {
38545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->device_extensions.wsi_enabled = true;
3855bee1d36c54af112766d4e8552ad302f39290683aMark Lobodzinski        }
3856bee1d36c54af112766d4e8552ad302f39290683aMark Lobodzinski        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME) == 0) {
3857c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young            dev_data->device_extensions.wsi_display_swapchain_enabled = true;
3858bee1d36c54af112766d4e8552ad302f39290683aMark Lobodzinski        }
3859bee1d36c54af112766d4e8552ad302f39290683aMark Lobodzinski        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_NV_GLSL_SHADER_EXTENSION_NAME) == 0) {
3860bee1d36c54af112766d4e8552ad302f39290683aMark Lobodzinski            dev_data->device_extensions.nv_glsl_shader_enabled = true;
3861bee1d36c54af112766d4e8552ad302f39290683aMark Lobodzinski        }
38626246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME) == 0) {
38636246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski            dev_data->device_extensions.khr_descriptor_update_template_enabled = true;
38646246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        }
386581b2d76c449bb91569776e2b8e68130f509d53bcChris Forbes        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME) == 0) {
386681b2d76c449bb91569776e2b8e68130f509d53bcChris Forbes            dev_data->device_extensions.khr_shader_draw_parameters_enabled = true;
386781b2d76c449bb91569776e2b8e68130f509d53bcChris Forbes        }
38680e2296e24065d02615ee87561bbb80af414a1ddfMike Schuchardt        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_MAINTENANCE1_EXTENSION_NAME) == 0) {
38690e2296e24065d02615ee87561bbb80af414a1ddfMike Schuchardt            dev_data->device_extensions.khr_maintenance1_enabled = true;
38700e2296e24065d02615ee87561bbb80af414a1ddfMike Schuchardt        }
38712664122d97c3f0a98b3e5d12833bbb20196ca837Mark Lobodzinski        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_NV_GEOMETRY_SHADER_PASSTHROUGH_EXTENSION_NAME) == 0) {
38722664122d97c3f0a98b3e5d12833bbb20196ca837Mark Lobodzinski            dev_data->device_extensions.nv_geometry_shader_passthrough_enabled = true;
38732664122d97c3f0a98b3e5d12833bbb20196ca837Mark Lobodzinski        }
38745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
38755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
38765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3877838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski// Verify that queue family has been properly requested
3878ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblenstatic bool ValidateRequestedQueueFamilyProperties(instance_layer_data *instance_data, VkPhysicalDevice gpu,
3879ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                                                   const VkDeviceCreateInfo *create_info) {
3880838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski    bool skip_call = false;
38819a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, gpu);
3882838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski    // First check is app has actually requested queueFamilyProperties
38834b293996aa6a9bd92ef1f0175eca4b0e8a9fd9fcChris Forbes    if (!physical_device_state) {
3884bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        skip_call |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
3885bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVLIMITS_MUST_QUERY_COUNT, "DL",
3886838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski                             "Invalid call to vkCreateDevice() w/o first calling vkEnumeratePhysicalDevices().");
38874b293996aa6a9bd92ef1f0175eca4b0e8a9fd9fcChris Forbes    } else if (QUERY_DETAILS != physical_device_state->vkGetPhysicalDeviceQueueFamilyPropertiesState) {
3888838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski        // TODO: This is not called out as an invalid use in the spec so make more informative recommendation.
38894b293996aa6a9bd92ef1f0175eca4b0e8a9fd9fcChris Forbes        skip_call |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
3890838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski                             VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVLIMITS_INVALID_QUEUE_CREATE_REQUEST,
3891838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski                             "DL", "Call to vkCreateDevice() w/o first calling vkGetPhysicalDeviceQueueFamilyProperties().");
3892838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski    } else {
3893838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski        // Check that the requested queue properties are valid
3894838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski        for (uint32_t i = 0; i < create_info->queueCreateInfoCount; i++) {
3895838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski            uint32_t requestedIndex = create_info->pQueueCreateInfos[i].queueFamilyIndex;
38967d8b6ab1b68c397da50bad43deb1fba389ebace7Chris Forbes            if (requestedIndex >= physical_device_state->queue_family_properties.size()) {
3897838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski                skip_call |= log_msg(
38984b293996aa6a9bd92ef1f0175eca4b0e8a9fd9fcChris Forbes                    instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0,
3899838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski                    __LINE__, DEVLIMITS_INVALID_QUEUE_CREATE_REQUEST, "DL",
3900838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski                    "Invalid queue create request in vkCreateDevice(). Invalid queueFamilyIndex %u requested.", requestedIndex);
3901838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski            } else if (create_info->pQueueCreateInfos[i].queueCount >
39027d8b6ab1b68c397da50bad43deb1fba389ebace7Chris Forbes                       physical_device_state->queue_family_properties[requestedIndex].queueCount) {
3903cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                skip_call |= log_msg(
3904cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0,
3905cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    __LINE__, DEVLIMITS_INVALID_QUEUE_CREATE_REQUEST, "DL",
3906cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "Invalid queue create request in vkCreateDevice(). QueueFamilyIndex %u only has %u queues, but "
3907cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "requested queueCount is %u.",
3908cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    requestedIndex, physical_device_state->queue_family_properties[requestedIndex].queueCount,
3909cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    create_info->pQueueCreateInfos[i].queueCount);
3910838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski            }
3911838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski        }
3912838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski    }
3913838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski    return skip_call;
3914838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski}
3915838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski
3916f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski// Verify that features have been queried and that they are available
3917bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool ValidateRequestedFeatures(instance_layer_data *dev_data, VkPhysicalDevice phys,
3918bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                      const VkPhysicalDeviceFeatures *requested_features) {
3919f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    bool skip_call = false;
3920f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
39219a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto phys_device_state = GetPhysicalDeviceState(dev_data, phys);
39223bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes    const VkBool32 *actual = reinterpret_cast<VkBool32 *>(&phys_device_state->features);
3923825ac70f99460ccb9494d34f93d8ee7ec303e5deMark Lobodzinski    const VkBool32 *requested = reinterpret_cast<const VkBool32 *>(requested_features);
3924f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    // TODO : This is a nice, compact way to loop through struct, but a bad way to report issues
3925f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    //  Need to provide the struct member name with the issue. To do that seems like we'll
3926f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    //  have to loop through each struct member which should be done w/ codegen to keep in synch.
3927f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    uint32_t errors = 0;
3928f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    uint32_t total_bools = sizeof(VkPhysicalDeviceFeatures) / sizeof(VkBool32);
3929f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    for (uint32_t i = 0; i < total_bools; i++) {
3930f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski        if (requested[i] > actual[i]) {
3931f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski            // TODO: Add index to struct member name helper to be able to include a feature name
3932cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            skip_call |=
3933cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0,
3934cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        __LINE__, DEVLIMITS_INVALID_FEATURE_REQUESTED, "DL",
3935cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "While calling vkCreateDevice(), requesting feature #%u in VkPhysicalDeviceFeatures struct, "
3936cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "which is not available on this device.",
3937cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        i);
3938f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski            errors++;
3939f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski        }
3940f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    }
39413bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes    if (errors && (UNCALLED == phys_device_state->vkGetPhysicalDeviceFeaturesState)) {
3942f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski        // If user didn't request features, notify them that they should
3943f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski        // TODO: Verify this against the spec. I believe this is an invalid use of the API and should return an error
3944bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
3945bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             0, __LINE__, DEVLIMITS_INVALID_FEATURE_REQUESTED, "DL",
3946bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             "You requested features that are unavailable on this device. You should first query feature "
3947bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             "availability by calling vkGetPhysicalDeviceFeatures().");
3948f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    }
3949f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    return skip_call;
3950f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski}
3951f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
395289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo,
395389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                            const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
395456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(gpu), instance_layer_data_map);
3955f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    bool skip_call = false;
3956f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
3957f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    // Check that any requested features are available
3958f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    if (pCreateInfo->pEnabledFeatures) {
395956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        skip_call |= ValidateRequestedFeatures(instance_data, gpu, pCreateInfo->pEnabledFeatures);
3960f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    }
396156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    skip_call |= ValidateRequestedQueueFamilyProperties(instance_data, gpu, pCreateInfo);
3962f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
39631d659b4113b77a95325df10d602a03f1e7abf8b7Mark Mueller    if (skip_call) {
39641d659b4113b77a95325df10d602a03f1e7abf8b7Mark Mueller        return VK_ERROR_VALIDATION_FAILED_EXT;
39651d659b4113b77a95325df10d602a03f1e7abf8b7Mark Mueller    }
39661d659b4113b77a95325df10d602a03f1e7abf8b7Mark Mueller
39675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkLayerDeviceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
39685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
39695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(chain_info->u.pLayerInfo);
39705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
39715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;
397256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(instance_data->instance, "vkCreateDevice");
39735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (fpCreateDevice == NULL) {
39745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return VK_ERROR_INITIALIZATION_FAILED;
39755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
39765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
39775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Advance the link info for the next element on the chain
39785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
39795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
39805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = fpCreateDevice(gpu, pCreateInfo, pAllocator, pDevice);
39815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result != VK_SUCCESS) {
39825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return result;
39835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
39845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3985b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
398656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(*pDevice), layer_data_map);
39875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
398856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    device_data->instance_data = instance_data;
39895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Setup device dispatch table
399056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_init_device_dispatch_table(*pDevice, &device_data->dispatch_table, fpGetDeviceProcAddr);
399156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    device_data->device = *pDevice;
3992ec85232c4d8d9ddf7d2ae57cb8203c5ab52c1106Mark Lobodzinski    // Save PhysicalDevice handle
399356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    device_data->physical_device = gpu;
39945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
399556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    device_data->report_data = layer_debug_report_create_device(instance_data->report_data, *pDevice);
3996373469f006399d6b5204ee05db3b56beb168b36fMark Young    checkDeviceRegisterExtensions(pCreateInfo, *pDevice);
39975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Get physical device limits for this device
399856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceProperties(gpu, &(device_data->phys_dev_properties.properties));
39995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t count;
400056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties(gpu, &count, nullptr);
400156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    device_data->phys_dev_properties.queue_family_properties.resize(count);
400256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties(
400356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        gpu, &count, &device_data->phys_dev_properties.queue_family_properties[0]);
40045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO: device limits should make sure these are compatible
40055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCreateInfo->pEnabledFeatures) {
400656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        device_data->enabled_features = *pCreateInfo->pEnabledFeatures;
40075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
400856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        memset(&device_data->enabled_features, 0, sizeof(VkPhysicalDeviceFeatures));
40095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
4010e47dbc3f3340fa177d877a67b2adb76a570027e5Mark Lobodzinski    // Store physical device properties and physical device mem limits into device layer_data structs
401156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceMemoryProperties(gpu, &device_data->phys_dev_mem_props);
401256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceProperties(gpu, &device_data->phys_dev_props);
4013b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
40145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
40155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    ValidateLayerOrdering(*pCreateInfo);
40165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
40175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
40185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
40195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
40205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// prototype
402189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL DestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) {
40225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODOSC : Shouldn't need any customization here
40233ec39aeb6d6f08fb1ee45f64f72543a710754c62Tobin Ehlis    bool skip = false;
40245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dispatch_key key = get_dispatch_key(device);
402556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(key, layer_data_map);
40265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Free all the memory
4027b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
40285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    deletePipelines(dev_data);
4029fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    dev_data->renderPassMap.clear();
40305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    deleteCommandBuffers(dev_data);
4031f13bee0887f3c3d1d597c82869864be3be836737Tobin Ehlis    // This will also delete all sets in the pool & remove them from setMap
40325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    deletePools(dev_data);
4033f13bee0887f3c3d1d597c82869864be3be836737Tobin Ehlis    // All sets should be removed
4034f13bee0887f3c3d1d597c82869864be3be836737Tobin Ehlis    assert(dev_data->setMap.empty());
4035a1e5173c89eb7f03e0434ad45ccd1471e722fa71Tobin Ehlis    for (auto del_layout : dev_data->descriptorSetLayoutMap) {
4036a1e5173c89eb7f03e0434ad45ccd1471e722fa71Tobin Ehlis        delete del_layout.second;
4037a1e5173c89eb7f03e0434ad45ccd1471e722fa71Tobin Ehlis    }
4038fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis    dev_data->descriptorSetLayoutMap.clear();
40395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->imageViewMap.clear();
40405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->imageMap.clear();
40415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->imageSubresourceMap.clear();
40425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->imageLayoutMap.clear();
40435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->bufferViewMap.clear();
40445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->bufferMap.clear();
40451344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis    // Queues persist until device is destroyed
40461344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis    dev_data->queueMap.clear();
40475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Report any memory leaks
40485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_debug_report_destroy_device(device);
4049b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
40505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
40515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#if DISPATCH_MAP_DEBUG
4052414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller    fprintf(stderr, "Device: 0x%p, key: 0x%p\n", device, key);
40535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#endif
40543ec39aeb6d6f08fb1ee45f64f72543a710754c62Tobin Ehlis    if (!skip) {
40554a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyDevice(device, pAllocator);
40563ec39aeb6d6f08fb1ee45f64f72543a710754c62Tobin Ehlis        layer_data_map.erase(key);
40575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
40585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
40595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
40605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic const VkExtensionProperties instance_extensions[] = {{VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION}};
40615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4062208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis// For given stage mask, if Geometry shader stage is on w/o GS being enabled, report geo_error_id
4063208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis//   and if Tessellation Control or Evaluation shader stages are on w/o TS being enabled, report tess_error_id
4064208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlisstatic bool ValidateStageMaskGsTsEnables(layer_data *dev_data, VkPipelineStageFlags stageMask, const char *caller,
4065208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                                         UNIQUE_VALIDATION_ERROR_CODE geo_error_id, UNIQUE_VALIDATION_ERROR_CODE tess_error_id) {
4066208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    bool skip = false;
4067208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    if (!dev_data->enabled_features.geometryShader && (stageMask & VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT)) {
4068208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
4069cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        geo_error_id, "DL",
4070cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "%s call includes a stageMask with VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT bit set when "
4071cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "device does not have geometryShader feature enabled. %s",
4072208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                        caller, validation_error_map[geo_error_id]);
4073208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    }
4074208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    if (!dev_data->enabled_features.tessellationShader &&
4075208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        (stageMask & (VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT | VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT))) {
4076208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
4077cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        tess_error_id, "DL",
4078cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "%s call includes a stageMask with VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT "
4079cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "and/or VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT bit(s) set when device "
4080cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "does not have tessellationShader feature enabled. %s",
4081208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                        caller, validation_error_map[tess_error_id]);
4082208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    }
4083208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    return skip;
4084208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis}
4085208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis
4086ad97d033b614e6265aaa8c8f0d21a044982d4de7Jeremy Hayes// Loop through bound objects and increment their in_use counts.
4087ad97d033b614e6265aaa8c8f0d21a044982d4de7Jeremy Hayesstatic void IncrementBoundObjects(layer_data *dev_data, GLOBAL_CB_NODE const *cb_node) {
4088a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    for (auto obj : cb_node->object_bindings) {
4089a317e7593a0fe227635fc8241908471acb36c952Chris Forbes        auto base_obj = GetStateStructPtrFromObject(dev_data, obj);
4090ad97d033b614e6265aaa8c8f0d21a044982d4de7Jeremy Hayes        if (base_obj) {
409151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            base_obj->in_use.fetch_add(1);
4092162dac96d3883e8fffaa1f988043f62c06662d2eTobin Ehlis        }
4093a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    }
4094a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis}
40955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Track which resources are in-flight by atomically incrementing their "in_use" count
409651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic void incrementResources(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
409751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    cb_node->submitCount++;
40989a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis    cb_node->in_use.fetch_add(1);
40999a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis    dev_data->globalInFlightCmdBuffers.insert(cb_node->commandBuffer);
4100a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
4101a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    // First Increment for all "generic" objects bound to cmd buffer, followed by special-case objects below
4102ad97d033b614e6265aaa8c8f0d21a044982d4de7Jeremy Hayes    IncrementBoundObjects(dev_data, cb_node);
4103a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    // TODO : We should be able to remove the NULL look-up checks from the code below as long as
4104a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    //  all the corresponding cases are verified to cause CB_INVALID state and the CB_INVALID state
4105a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    //  should then be flagged prior to calling this function
41069a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis    for (auto drawDataElement : cb_node->drawData) {
41075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto buffer : drawDataElement.buffers) {
41089a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto buffer_state = GetBufferState(dev_data, buffer);
410951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            if (buffer_state) {
41105cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis                buffer_state->in_use.fetch_add(1);
41115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
41125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
41135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
41149a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis    for (auto event : cb_node->writeEventsBeforeWait) {
41159a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto event_state = GetEventNode(dev_data, event);
4116cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (event_state) event_state->write_in_use++;
4117c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    }
41185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
41195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4120b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis// Note: This function assumes that the global lock is held by the calling thread.
4121b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis// For the given queue, verify the queue state up to the given seq number.
4122b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis// Currently the only check is to make sure that if there are events to be waited on prior to
4123b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis//  a QueryReset, make sure that all such events have been signalled.
412436c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic bool VerifyQueueStateToSeq(layer_data *dev_data, QUEUE_STATE *queue, uint64_t seq) {
4125b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    bool skip = false;
4126b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    auto queue_seq = queue->seq;
412792b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis    std::unordered_map<VkQueue, uint64_t> other_queue_seqs;
412892b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis    auto sub_it = queue->submissions.begin();
4129b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    while (queue_seq < seq) {
413092b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis        for (auto &wait : sub_it->waitSemaphores) {
413192b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis            auto &last_seq = other_queue_seqs[wait.queue];
413292b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis            last_seq = std::max(last_seq, wait.seq);
413392b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis        }
413492b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis        for (auto cb : sub_it->cbs) {
41359a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto cb_node = GetCBNode(dev_data, cb);
4136b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis            if (cb_node) {
4137b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                for (auto queryEventsPair : cb_node->waitedEventsBeforeQueryReset) {
4138b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                    for (auto event : queryEventsPair.second) {
413992b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis                        if (dev_data->eventMap[event].needsSignaled) {
414092b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis                            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
4141b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                                            VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, 0, DRAWSTATE_INVALID_QUERY, "DS",
4142b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                                            "Cannot get query results on queryPool 0x%" PRIx64
4143b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                                            " with index %d which was guarded by unsignaled event 0x%" PRIx64 ".",
4144b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                                            (uint64_t)(queryEventsPair.first.pool), queryEventsPair.first.index, (uint64_t)(event));
4145b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                        }
4146b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                    }
4147b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine                }
4148b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine            }
4149b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine        }
415092b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis        sub_it++;
4151b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis        queue_seq++;
4152b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine    }
415392b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis    for (auto qs : other_queue_seqs) {
41549a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        skip |= VerifyQueueStateToSeq(dev_data, GetQueueState(dev_data, qs.first), qs.second);
415592b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis    }
4156b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    return skip;
4157b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis}
4158b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis
4159b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis// When the given fence is retired, verify outstanding queue operations through the point of the fence
4160b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlisstatic bool VerifyQueueStateToFence(layer_data *dev_data, VkFence fence) {
41619a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto fence_state = GetFenceNode(dev_data, fence);
4162b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    if (VK_NULL_HANDLE != fence_state->signaler.first) {
41639a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        return VerifyQueueStateToSeq(dev_data, GetQueueState(dev_data, fence_state->signaler.first), fence_state->signaler.second);
4164b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    }
4165b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    return false;
4166b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine}
41677d33205c3aa4aba751a2c07f956634aac616f916Chris Forbes
41687d33205c3aa4aba751a2c07f956634aac616f916Chris Forbes// TODO: nuke this completely.
4169b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine// Decrement cmd_buffer in_use and if it goes to 0 remove cmd_buffer from globalInFlightCmdBuffers
4170b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentinestatic inline void removeInFlightCmdBuffer(layer_data *dev_data, VkCommandBuffer cmd_buffer) {
4171b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine    // Pull it off of global list initially, but if we find it in any other queue list, add it back in
41729a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, cmd_buffer);
4173b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine    pCB->in_use.fetch_sub(1);
4174b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine    if (!pCB->in_use.load()) {
4175b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine        dev_data->globalInFlightCmdBuffers.erase(cmd_buffer);
4176b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine    }
4177b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine}
4178b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine
4179a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis// Decrement in-use count for objects bound to command buffer
41802f8cbf3b166e175174877a59929902e005953d6dTobin Ehlisstatic void DecrementBoundResources(layer_data *dev_data, GLOBAL_CB_NODE const *cb_node) {
418100e8ce2e6c1c191758f7b7c15eeaf350e5b4a3b6Tobin Ehlis    BASE_NODE *base_obj = nullptr;
4182a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    for (auto obj : cb_node->object_bindings) {
41837e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis        base_obj = GetStateStructPtrFromObject(dev_data, obj);
418400e8ce2e6c1c191758f7b7c15eeaf350e5b4a3b6Tobin Ehlis        if (base_obj) {
418500e8ce2e6c1c191758f7b7c15eeaf350e5b4a3b6Tobin Ehlis            base_obj->in_use.fetch_sub(1);
418600e8ce2e6c1c191758f7b7c15eeaf350e5b4a3b6Tobin Ehlis        }
4187a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    }
4188a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis}
4189da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes
419036c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic void RetireWorkOnQueue(layer_data *dev_data, QUEUE_STATE *pQueue, uint64_t seq) {
41919867daedbf52debc77d6568162ee21e071699b80Chris Forbes    std::unordered_map<VkQueue, uint64_t> otherQueueSeqs;
41929867daedbf52debc77d6568162ee21e071699b80Chris Forbes
41939867daedbf52debc77d6568162ee21e071699b80Chris Forbes    // Roll this queue forward, one submission at a time.
41949867daedbf52debc77d6568162ee21e071699b80Chris Forbes    while (pQueue->seq < seq) {
4195bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto &submission = pQueue->submissions.front();
41969867daedbf52debc77d6568162ee21e071699b80Chris Forbes
4197bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        for (auto &wait : submission.waitSemaphores) {
41989a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, wait.semaphore);
4199c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            if (pSemaphore) {
4200c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski                pSemaphore->in_use.fetch_sub(1);
4201c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            }
4202bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            auto &lastSeq = otherQueueSeqs[wait.queue];
42039867daedbf52debc77d6568162ee21e071699b80Chris Forbes            lastSeq = std::max(lastSeq, wait.seq);
4204da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes        }
4205cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes
4206bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        for (auto &semaphore : submission.signalSemaphores) {
42079a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
4208c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            if (pSemaphore) {
4209c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski                pSemaphore->in_use.fetch_sub(1);
4210c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            }
42119867daedbf52debc77d6568162ee21e071699b80Chris Forbes        }
4212cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes
42139867daedbf52debc77d6568162ee21e071699b80Chris Forbes        for (auto cb : submission.cbs) {
42149a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto cb_node = GetCBNode(dev_data, cb);
4215c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            if (!cb_node) {
4216c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski                continue;
4217c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            }
4218a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis            // First perform decrement on general case bound objects
42199a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            DecrementBoundResources(dev_data, cb_node);
42209a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            for (auto drawDataElement : cb_node->drawData) {
42219867daedbf52debc77d6568162ee21e071699b80Chris Forbes                for (auto buffer : drawDataElement.buffers) {
42229a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto buffer_state = GetBufferState(dev_data, buffer);
42235cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis                    if (buffer_state) {
42245cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis                        buffer_state->in_use.fetch_sub(1);
42259867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    }
42269867daedbf52debc77d6568162ee21e071699b80Chris Forbes                }
4227da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes            }
42289a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            for (auto event : cb_node->writeEventsBeforeWait) {
42299867daedbf52debc77d6568162ee21e071699b80Chris Forbes                auto eventNode = dev_data->eventMap.find(event);
42309867daedbf52debc77d6568162ee21e071699b80Chris Forbes                if (eventNode != dev_data->eventMap.end()) {
42319867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    eventNode->second.write_in_use--;
42329867daedbf52debc77d6568162ee21e071699b80Chris Forbes                }
42339867daedbf52debc77d6568162ee21e071699b80Chris Forbes            }
42349a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            for (auto queryStatePair : cb_node->queryToStateMap) {
42359867daedbf52debc77d6568162ee21e071699b80Chris Forbes                dev_data->queryToStateMap[queryStatePair.first] = queryStatePair.second;
42369867daedbf52debc77d6568162ee21e071699b80Chris Forbes            }
42379a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            for (auto eventStagePair : cb_node->eventToStageMap) {
42389867daedbf52debc77d6568162ee21e071699b80Chris Forbes                dev_data->eventMap[eventStagePair.first].stageMask = eventStagePair.second;
4239da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes            }
42400a32ed7bdf03e7bda914e03c0bfa6ebf400cdf5bMichael Lentine
42419867daedbf52debc77d6568162ee21e071699b80Chris Forbes            removeInFlightCmdBuffer(dev_data, cb);
42420a32ed7bdf03e7bda914e03c0bfa6ebf400cdf5bMichael Lentine        }
42439867daedbf52debc77d6568162ee21e071699b80Chris Forbes
42449a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto pFence = GetFenceNode(dev_data, submission.fence);
42459867daedbf52debc77d6568162ee21e071699b80Chris Forbes        if (pFence) {
42469867daedbf52debc77d6568162ee21e071699b80Chris Forbes            pFence->state = FENCE_RETIRED;
42470a32ed7bdf03e7bda914e03c0bfa6ebf400cdf5bMichael Lentine        }
42489867daedbf52debc77d6568162ee21e071699b80Chris Forbes
42499867daedbf52debc77d6568162ee21e071699b80Chris Forbes        pQueue->submissions.pop_front();
42509867daedbf52debc77d6568162ee21e071699b80Chris Forbes        pQueue->seq++;
4251b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
42529867daedbf52debc77d6568162ee21e071699b80Chris Forbes
42539867daedbf52debc77d6568162ee21e071699b80Chris Forbes    // Roll other queues forward to the highest seq we saw a wait for
42549867daedbf52debc77d6568162ee21e071699b80Chris Forbes    for (auto qs : otherQueueSeqs) {
42559a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        RetireWorkOnQueue(dev_data, GetQueueState(dev_data, qs.first), qs.second);
4256d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    }
42579867daedbf52debc77d6568162ee21e071699b80Chris Forbes}
4258651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
4259651d92815dfff917308137bb67aacccc4f60df86Chris Forbes// Submit a fence to a queue, delimiting previous fences and previous untracked
4260651d92815dfff917308137bb67aacccc4f60df86Chris Forbes// work by it.
426136c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic void SubmitFence(QUEUE_STATE *pQueue, FENCE_NODE *pFence, uint64_t submitCount) {
4262cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes    pFence->state = FENCE_INFLIGHT;
42639867daedbf52debc77d6568162ee21e071699b80Chris Forbes    pFence->signaler.first = pQueue->queue;
42649867daedbf52debc77d6568162ee21e071699b80Chris Forbes    pFence->signaler.second = pQueue->seq + pQueue->submissions.size() + submitCount;
4265b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine}
4266b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine
426751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic bool validateCommandBufferSimultaneousUse(layer_data *dev_data, GLOBAL_CB_NODE *pCB, int current_submit_count) {
42685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool skip_call = false;
426951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    if ((dev_data->globalInFlightCmdBuffers.count(pCB->commandBuffer) || current_submit_count > 1) &&
42705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
4271226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
4272f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                             0, __LINE__, VALIDATION_ERROR_00133, "DS",
4273f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                             "Command Buffer 0x%p is already in use and is not marked for simultaneous use. %s", pCB->commandBuffer,
4274f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                             validation_error_map[VALIDATION_ERROR_00133]);
42755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
42765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
42775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
42785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4279946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinskistatic bool validateCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, const char *call_source,
4280440bdd357701497c3442e3515f12ac1cfffc180aTony Barbour                                       int current_submit_count) {
4281c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis    bool skip = false;
4282cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.command_buffer_state) return skip;
42830a59acde4b40fde3bbfea5811d2abf2c85ca62f4Tobin Ehlis    // Validate ONE_TIME_SUBMIT_BIT CB is not being submitted more than once
4284946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if ((cb_state->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) &&
4285946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        (cb_state->submitCount + current_submit_count > 1)) {
4286c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
4287c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis                        __LINE__, DRAWSTATE_COMMAND_BUFFER_SINGLE_SUBMIT_VIOLATION, "DS",
4288226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "Commandbuffer 0x%p was begun w/ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT "
4289c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis                        "set, but has been submitted 0x%" PRIxLEAST64 " times.",
4290946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        cb_state->commandBuffer, cb_state->submitCount + current_submit_count);
42910a59acde4b40fde3bbfea5811d2abf2c85ca62f4Tobin Ehlis    }
42925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Validate that cmd buffers have been updated
4293946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (CB_RECORDED != cb_state->state) {
4294946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        if (CB_INVALID == cb_state->state) {
4295946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            skip |= ReportInvalidCommandBuffer(dev_data, cb_state, call_source);
4296cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        } else {  // Flag error for using CB w/o vkEndCommandBuffer() called
4297c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
4298946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            (uint64_t)(cb_state->commandBuffer), __LINE__, DRAWSTATE_NO_END_COMMAND_BUFFER, "DS",
4299946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            "You must call vkEndCommandBuffer() on command buffer 0x%p before this call to %s!",
4300946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            cb_state->commandBuffer, call_source);
43015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
43025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
4303c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis    return skip;
43045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
43055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
430651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic bool validateResources(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
430751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    bool skip_call = false;
430851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
430951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    // TODO : We should be able to remove the NULL look-up checks from the code below as long as
431051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    //  all the corresponding cases are verified to cause CB_INVALID state and the CB_INVALID state
431151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    //  should then be flagged prior to calling this function
431251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    for (auto drawDataElement : cb_node->drawData) {
431351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        for (auto buffer : drawDataElement.buffers) {
431451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            auto buffer_state = GetBufferState(dev_data, buffer);
431551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            if (!buffer_state) {
431651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
431751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                                     (uint64_t)(buffer), __LINE__, DRAWSTATE_INVALID_BUFFER, "DS",
431851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                                     "Cannot submit cmd buffer using deleted buffer 0x%" PRIx64 ".", (uint64_t)(buffer));
431951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            }
432051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        }
432151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    }
432251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    return skip_call;
432351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour}
432451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
4325f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski// Check that the queue family index of 'queue' matches one of the entries in pQueueFamilyIndices
4326f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinskibool ValidImageBufferQueue(layer_data *dev_data, GLOBAL_CB_NODE *cb_node, const VK_OBJECT *object, VkQueue queue, uint32_t count,
4327f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                           const uint32_t *indices) {
4328f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski    bool found = false;
4329f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski    bool skip = false;
4330f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski    auto queue_state = GetQueueState(dev_data, queue);
4331f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski    if (queue_state) {
4332f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        for (uint32_t i = 0; i < count; i++) {
4333f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski            if (indices[i] == queue_state->queueFamilyIndex) {
4334f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                found = true;
4335f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                break;
4336f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski            }
4337f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        }
4338f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski
4339f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        if (!found) {
4340f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski            auto type_string = (object->type == VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT ? "image" : "buffer");
4341f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski            skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, object->type, object->handle, __LINE__,
4342f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                           DRAWSTATE_INVALID_QUEUE_FAMILY, "DS",
4343f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                           "vkQueueSubmit: Command buffer 0x%" PRIxLEAST64 " contains %s 0x%" PRIxLEAST64
4344f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                           " which was not created allowing concurrent access to this queue family %d.",
4345f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                           reinterpret_cast<uint64_t>(cb_node->commandBuffer), type_string, object->handle,
4346f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                           queue_state->queueFamilyIndex);
4347f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        }
4348f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski    }
4349f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski    return skip;
4350f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski}
4351f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski
43527bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski// Validate that queueFamilyIndices of primary command buffers match this queue
43537bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski// Secondary command buffers were previously validated in vkCmdExecuteCommands().
43547bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinskistatic bool validateQueueFamilyIndices(layer_data *dev_data, GLOBAL_CB_NODE *pCB, VkQueue queue) {
43557bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski    bool skip_call = false;
43569a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pPool = GetCommandPoolNode(dev_data, pCB->createInfo.commandPool);
43579a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto queue_state = GetQueueState(dev_data, queue);
43587bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
4359f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski    if (pPool && queue_state) {
4360f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        if (pPool->queueFamilyIndex != queue_state->queueFamilyIndex) {
4361f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski            skip_call |=
4362f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
4363f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                        reinterpret_cast<uint64_t>(pCB->commandBuffer), __LINE__, VALIDATION_ERROR_00139, "DS",
4364f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                        "vkQueueSubmit: Primary command buffer 0x%p created in queue family %d is being submitted on queue "
4365f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                        "0x%p from queue family %d. %s",
4366f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                        pCB->commandBuffer, pPool->queueFamilyIndex, queue, queue_state->queueFamilyIndex,
4367f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                        validation_error_map[VALIDATION_ERROR_00139]);
4368f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        }
4369f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski
4370f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        // Ensure that any bound images or buffers created with SHARING_MODE_CONCURRENT have access to the current queue family
4371f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        for (auto object : pCB->object_bindings) {
4372f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski            if (object.type == VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT) {
4373f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                auto image_state = GetImageState(dev_data, reinterpret_cast<VkImage &>(object.handle));
4374f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                if (image_state && image_state->createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) {
4375f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                    skip_call |= ValidImageBufferQueue(dev_data, pCB, &object, queue, image_state->createInfo.queueFamilyIndexCount,
4376f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                                                       image_state->createInfo.pQueueFamilyIndices);
4377f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                }
4378f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski            } else if (object.type == VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT) {
4379f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                auto buffer_state = GetBufferState(dev_data, reinterpret_cast<VkBuffer &>(object.handle));
4380f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                if (buffer_state && buffer_state->createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) {
4381f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                    skip_call |=
4382f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                        ValidImageBufferQueue(dev_data, pCB, &object, queue, buffer_state->createInfo.queueFamilyIndexCount,
4383f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                                              buffer_state->createInfo.pQueueFamilyIndices);
4384f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                }
4385f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski            }
4386f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        }
43877bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski    }
43887bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
43897bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski    return skip_call;
43907bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski}
43917bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
439251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic bool validatePrimaryCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB, int current_submit_count) {
43935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Track in-use for resources off of primary and any secondary CBs
439483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
4395a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
4396a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes    // If USAGE_SIMULTANEOUS_USE_BIT not set then CB cannot already be executing
4397a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes    // on device
439851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    skip_call |= validateCommandBufferSimultaneousUse(dev_data, pCB, current_submit_count);
4399a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
440051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    skip_call |= validateResources(dev_data, pCB);
4401a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
44025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (!pCB->secondaryCommandBuffers.empty()) {
44035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto secondaryCmdBuffer : pCB->secondaryCommandBuffers) {
44049a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            GLOBAL_CB_NODE *pSubCB = GetCBNode(dev_data, secondaryCmdBuffer);
440551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            skip_call |= validateResources(dev_data, pSubCB);
44064c665b29a9d2906a378417546c7fc6436731d07fTobin Ehlis            if ((pSubCB->primaryCommandBuffer != pCB->commandBuffer) &&
44074c665b29a9d2906a378417546c7fc6436731d07fTobin Ehlis                !(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
4408f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                log_msg(
4409f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
4410f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    __LINE__, VALIDATION_ERROR_00135, "DS",
4411f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    "Commandbuffer 0x%p was submitted with secondary buffer 0x%p but that buffer has subsequently been bound to "
4412f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    "primary cmd buffer 0x%p and it does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set. %s",
4413f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    pCB->commandBuffer, secondaryCmdBuffer, pSubCB->primaryCommandBuffer,
4414f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    validation_error_map[VALIDATION_ERROR_00135]);
44155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
44165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
44175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
4418a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
441951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    skip_call |= validateCommandBufferState(dev_data, pCB, "vkQueueSubmit()", current_submit_count);
4420a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
442183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
44225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
44235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4424bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool ValidateFenceForSubmit(layer_data *dev_data, FENCE_NODE *pFence) {
442583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
442681c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes
4427651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    if (pFence) {
4428cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes        if (pFence->state == FENCE_INFLIGHT) {
4429f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen            // TODO: opportunities for VALIDATION_ERROR_00127, VALIDATION_ERROR_01647, VALIDATION_ERROR_01953
443083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
443183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 (uint64_t)(pFence->fence), __LINE__, DRAWSTATE_INVALID_FENCE, "DS",
443283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 "Fence 0x%" PRIx64 " is already in use by another submission.", (uint64_t)(pFence->fence));
4433a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        }
443481c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes
4435cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes        else if (pFence->state == FENCE_RETIRED) {
4436f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen            // TODO: opportunities for VALIDATION_ERROR_00126, VALIDATION_ERROR_01646, VALIDATION_ERROR_01953
443783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |=
443883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
443983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                        reinterpret_cast<uint64_t &>(pFence->fence), __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM",
444083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                        "Fence 0x%" PRIxLEAST64 " submitted in SIGNALED state.  Fences must be reset before being submitted",
444183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                        reinterpret_cast<uint64_t &>(pFence->fence));
4442a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        }
44435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
444481c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes
444583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
444681c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes}
444781c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes
444851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic void PostCallRecordQueueSubmit(layer_data *dev_data, VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits,
444951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                                      VkFence fence) {
44509a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pQueue = GetQueueState(dev_data, queue);
44519a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pFence = GetFenceNode(dev_data, fence);
4452d7d60cccc862fee2d0b3ad410c5fdcc40ddc83aeChris Forbes
4453651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    // Mark the fence in-use.
4454651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    if (pFence) {
44559867daedbf52debc77d6568162ee21e071699b80Chris Forbes        SubmitFence(pQueue, pFence, std::max(1u, submitCount));
4456651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    }
4457651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
445851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    // Now process each individual submit
44595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
446051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        std::vector<VkCommandBuffer> cbs;
44615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubmitInfo *submit = &pSubmits[submit_idx];
44629867daedbf52debc77d6568162ee21e071699b80Chris Forbes        vector<SEMAPHORE_WAIT> semaphore_waits;
44639867daedbf52debc77d6568162ee21e071699b80Chris Forbes        vector<VkSemaphore> semaphore_signals;
44645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < submit->waitSemaphoreCount; ++i) {
446551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            VkSemaphore semaphore = submit->pWaitSemaphores[i];
446651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
446751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            if (pSemaphore) {
446851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                if (pSemaphore->signaler.first != VK_NULL_HANDLE) {
446951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    semaphore_waits.push_back({semaphore, pSemaphore->signaler.first, pSemaphore->signaler.second});
447051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    pSemaphore->in_use.fetch_add(1);
447151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                }
447251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->signaler.first = VK_NULL_HANDLE;
447351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->signaled = false;
447451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            }
447551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        }
447651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        for (uint32_t i = 0; i < submit->signalSemaphoreCount; ++i) {
447751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            VkSemaphore semaphore = submit->pSignalSemaphores[i];
447851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
447951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            if (pSemaphore) {
448051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->signaler.first = queue;
448151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->signaler.second = pQueue->seq + pQueue->submissions.size() + 1;
448251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->signaled = true;
448351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->in_use.fetch_add(1);
448451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                semaphore_signals.push_back(semaphore);
448551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            }
448651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        }
448751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        for (uint32_t i = 0; i < submit->commandBufferCount; i++) {
448851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            auto cb_node = GetCBNode(dev_data, submit->pCommandBuffers[i]);
448951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            if (cb_node) {
449051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                cbs.push_back(submit->pCommandBuffers[i]);
449151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                for (auto secondaryCmdBuffer : cb_node->secondaryCommandBuffers) {
449251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    cbs.push_back(secondaryCmdBuffer);
449351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                }
449451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                UpdateCmdBufImageLayouts(dev_data, cb_node);
449551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                incrementResources(dev_data, cb_node);
449651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                if (!cb_node->secondaryCommandBuffers.empty()) {
449751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    for (auto secondaryCmdBuffer : cb_node->secondaryCommandBuffers) {
449851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                        GLOBAL_CB_NODE *pSubCB = GetCBNode(dev_data, secondaryCmdBuffer);
449951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                        incrementResources(dev_data, pSubCB);
450051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    }
450151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                }
450251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            }
450351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        }
450451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        pQueue->submissions.emplace_back(cbs, semaphore_waits, semaphore_signals,
450551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                                         submit_idx == submitCount - 1 ? fence : VK_NULL_HANDLE);
450651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    }
450751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
450851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    if (pFence && !submitCount) {
450951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        // If no submissions, but just dropping a fence on the end of the queue,
451051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        // record an empty submission with just the fence, so we can determine
451151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        // its completion.
451251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        pQueue->submissions.emplace_back(std::vector<VkCommandBuffer>(), std::vector<SEMAPHORE_WAIT>(), std::vector<VkSemaphore>(),
451351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                                         fence);
451451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    }
451551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour}
451651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
451751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic bool PreCallValidateQueueSubmit(layer_data *dev_data, VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits,
451851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                                       VkFence fence) {
451951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    auto pFence = GetFenceNode(dev_data, fence);
452051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    bool skip_call = ValidateFenceForSubmit(dev_data, pFence);
452151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    if (skip_call) {
452251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        return true;
452351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    }
452451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
452551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    unordered_set<VkSemaphore> signaled_semaphores;
452651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    unordered_set<VkSemaphore> unsignaled_semaphores;
452751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    vector<VkCommandBuffer> current_cmds;
452851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> localImageLayoutMap = dev_data->imageLayoutMap;
452951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    // Now verify each individual submit
453051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
453151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        const VkSubmitInfo *submit = &pSubmits[submit_idx];
453251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        for (uint32_t i = 0; i < submit->waitSemaphoreCount; ++i) {
4533208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis            skip_call |= ValidateStageMaskGsTsEnables(dev_data, submit->pWaitDstStageMask[i], "vkQueueSubmit()",
4534208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                                                      VALIDATION_ERROR_00142, VALIDATION_ERROR_00143);
453501a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            VkSemaphore semaphore = submit->pWaitSemaphores[i];
45369a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
453701a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            if (pSemaphore) {
453851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                if (unsignaled_semaphores.count(semaphore) ||
4539440bdd357701497c3442e3515f12ac1cfffc180aTony Barbour                    (!(signaled_semaphores.count(semaphore)) && !(pSemaphore->signaled))) {
454083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |=
45411344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
45421344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                                reinterpret_cast<const uint64_t &>(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
4543226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                "Queue 0x%p is waiting on semaphore 0x%" PRIx64 " that has no way to be signaled.", queue,
4544226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                reinterpret_cast<const uint64_t &>(semaphore));
454551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                } else {
454651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    signaled_semaphores.erase(semaphore);
454751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    unsignaled_semaphores.insert(semaphore);
45481344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                }
45495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
45505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
45515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < submit->signalSemaphoreCount; ++i) {
455201a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            VkSemaphore semaphore = submit->pSignalSemaphores[i];
45539a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
455401a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            if (pSemaphore) {
4555440bdd357701497c3442e3515f12ac1cfffc180aTony Barbour                if (signaled_semaphores.count(semaphore) || (!(unsignaled_semaphores.count(semaphore)) && pSemaphore->signaled)) {
455683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |=
45571344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
45581344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                                reinterpret_cast<const uint64_t &>(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
4559226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                "Queue 0x%p is signaling semaphore 0x%" PRIx64
4560414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                                " that has already been signaled but not waited on by queue 0x%" PRIx64 ".",
4561226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                queue, reinterpret_cast<const uint64_t &>(semaphore),
45629867daedbf52debc77d6568162ee21e071699b80Chris Forbes                                reinterpret_cast<uint64_t &>(pSemaphore->signaler.first));
45631344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                } else {
456451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    unsignaled_semaphores.erase(semaphore);
456551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    signaled_semaphores.insert(semaphore);
45661344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                }
45670a32ed7bdf03e7bda914e03c0bfa6ebf400cdf5bMichael Lentine            }
45685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
45695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < submit->commandBufferCount; i++) {
45709a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto cb_node = GetCBNode(dev_data, submit->pCommandBuffers[i]);
4571d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis            if (cb_node) {
4572b34ce3b0eda520db569665ae02ec5f6f0e8b6fd1Mark Lobodzinski                skip_call |= ValidateCmdBufImageLayouts(dev_data, cb_node, localImageLayoutMap);
457351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                current_cmds.push_back(submit->pCommandBuffers[i]);
457451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                skip_call |= validatePrimaryCommandBufferState(
457551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    dev_data, cb_node, (int)std::count(current_cmds.begin(), current_cmds.end(), submit->pCommandBuffers[i]));
4576d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                skip_call |= validateQueueFamilyIndices(dev_data, cb_node, queue);
457751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
4578ea371fa7c8c57edb4d1436e4570cf54f3fc0463fTobin Ehlis                // Potential early exit here as bad object state may crash in delayed function calls
457951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                if (skip_call) {
458051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    return true;
458151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                }
458251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
45831344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                // Call submit-time functions to validate/update state
4584d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                for (auto &function : cb_node->validate_functions) {
458583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |= function();
45861344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                }
4587d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                for (auto &function : cb_node->eventUpdates) {
458883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |= function(queue);
45891344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                }
4590d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                for (auto &function : cb_node->queryUpdates) {
459183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |= function(queue);
4592d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                }
45931344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis            }
45945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
45959867daedbf52debc77d6568162ee21e071699b80Chris Forbes    }
459651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    return skip_call;
459751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour}
45989867daedbf52debc77d6568162ee21e071699b80Chris Forbes
459951920949f887ce8d3666c73c28ff19a5d8325a37Tony BarbourVKAPI_ATTR VkResult VKAPI_CALL QueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence) {
460051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
460151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    std::unique_lock<std::mutex> lock(global_lock);
460251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
460351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    bool skip = PreCallValidateQueueSubmit(dev_data, queue, submitCount, pSubmits, fence);
4604b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
46055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4606440bdd357701497c3442e3515f12ac1cfffc180aTony Barbour    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
460751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
460851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    VkResult result = dev_data->dispatch_table.QueueSubmit(queue, submitCount, pSubmits, fence);
460951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
461051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    lock.lock();
461151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    PostCallRecordQueueSubmit(dev_data, queue, submitCount, pSubmits, fence);
461251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    lock.unlock();
46135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
46145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
46155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4616f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultzstatic bool PreCallValidateAllocateMemory(layer_data *dev_data) {
4617f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    bool skip = false;
4618f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    if (dev_data->memObjMap.size() >= dev_data->phys_dev_properties.properties.limits.maxMemoryAllocationCount) {
4619f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
4620f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz                        reinterpret_cast<const uint64_t &>(dev_data->device), __LINE__, VALIDATION_ERROR_00611, "MEM",
4621f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz                        "Number of currently valid memory objects is not less than the maximum allowed (%u). %s",
4622f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz                        dev_data->phys_dev_properties.properties.limits.maxMemoryAllocationCount,
4623f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz                        validation_error_map[VALIDATION_ERROR_00611]);
4624f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    }
4625f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    return skip;
4626f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz}
4627f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz
4628f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultzstatic void PostCallRecordAllocateMemory(layer_data *dev_data, const VkMemoryAllocateInfo *pAllocateInfo, VkDeviceMemory *pMemory) {
4629f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    add_mem_obj_info(dev_data, dev_data->device, *pMemory, pAllocateInfo);
4630f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    return;
4631f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz}
4632f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz
463389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL AllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo,
463489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                              const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory) {
4635f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
463656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
4637f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    std::unique_lock<std::mutex> lock(global_lock);
4638f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    bool skip = PreCallValidateAllocateMemory(dev_data);
4639f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    if (!skip) {
4640f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        lock.unlock();
4641f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        result = dev_data->dispatch_table.AllocateMemory(device, pAllocateInfo, pAllocator, pMemory);
4642f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        lock.lock();
4643f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        if (VK_SUCCESS == result) {
4644f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz            PostCallRecordAllocateMemory(dev_data, pAllocateInfo, pMemory);
4645f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        }
4646e12739a56d02ca2fb5f0273862668e7475a21a6cMark Lobodzinski    }
46475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
46485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
46495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4650177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis// For given obj node, if it is use, flag a validation error and return callback result, else return false
4651177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlisbool ValidateObjectNotInUse(const layer_data *dev_data, BASE_NODE *obj_node, VK_OBJECT obj_struct,
4652177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis                            UNIQUE_VALIDATION_ERROR_CODE error_code) {
4653cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.object_in_use) return false;
4654177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    bool skip = false;
4655177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    if (obj_node->in_use.load()) {
4656177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, obj_struct.type, obj_struct.handle, __LINE__,
4657177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis                        error_code, "DS", "Cannot delete %s 0x%" PRIx64 " that is currently in use by a command buffer. %s",
4658177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis                        object_type_to_string(obj_struct.type), obj_struct.handle, validation_error_map[error_code]);
4659177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    }
4660177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    return skip;
4661177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis}
46625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4663177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlisstatic bool PreCallValidateFreeMemory(layer_data *dev_data, VkDeviceMemory mem, DEVICE_MEM_INFO **mem_info, VK_OBJECT *obj_struct) {
46649a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *mem_info = GetMemObjInfo(dev_data, mem);
466594165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(mem), VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT};
4666cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.free_memory) return false;
4667177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    bool skip = false;
4668177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    if (*mem_info) {
4669177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *mem_info, *obj_struct, VALIDATION_ERROR_00620);
4670177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    }
4671177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    return skip;
4672177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis}
46735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4674177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlisstatic void PostCallRecordFreeMemory(layer_data *dev_data, VkDeviceMemory mem, DEVICE_MEM_INFO *mem_info, VK_OBJECT obj_struct) {
4675177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    // Clear mem binding for any bound objects
467647705d01140c9f1492885e6efc5fa262e7e1c6a0Tobin Ehlis    for (auto obj : mem_info->obj_bindings) {
467747705d01140c9f1492885e6efc5fa262e7e1c6a0Tobin Ehlis        log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, obj.type, obj.handle, __LINE__, MEMTRACK_FREED_MEM_REF,
467847705d01140c9f1492885e6efc5fa262e7e1c6a0Tobin Ehlis                "MEM", "VK Object 0x%" PRIxLEAST64 " still has a reference to mem obj 0x%" PRIxLEAST64, obj.handle,
467947705d01140c9f1492885e6efc5fa262e7e1c6a0Tobin Ehlis                (uint64_t)mem_info->mem);
468047705d01140c9f1492885e6efc5fa262e7e1c6a0Tobin Ehlis        switch (obj.type) {
4681cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT: {
46829a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto image_state = GetImageState(dev_data, reinterpret_cast<VkImage &>(obj.handle));
4683cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                assert(image_state);  // Any destroyed images should already be removed from bindings
4684cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                image_state->binding.mem = MEMORY_UNBOUND;
4685cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4686cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4687cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT: {
46889a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto buffer_state = GetBufferState(dev_data, reinterpret_cast<VkBuffer &>(obj.handle));
4689cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                assert(buffer_state);  // Any destroyed buffers should already be removed from bindings
4690cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                buffer_state->binding.mem = MEMORY_UNBOUND;
4691cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4692cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4693cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
4694cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // Should only have buffer or image objects bound to memory
4695cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                assert(0);
4696177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        }
4697177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    }
4698177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    // Any bound cmd buffers are now invalid
469939c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, mem_info->cb_bindings, obj_struct);
4700177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    dev_data->memObjMap.erase(mem);
4701177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis}
4702177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis
4703177063aac84fac6f4e650c2629a08b48be643f96Tobin EhlisVKAPI_ATTR void VKAPI_CALL FreeMemory(VkDevice device, VkDeviceMemory mem, const VkAllocationCallbacks *pAllocator) {
470456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
4705177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    DEVICE_MEM_INFO *mem_info = nullptr;
4706177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    VK_OBJECT obj_struct;
4707b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
4708177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    bool skip = PreCallValidateFreeMemory(dev_data, mem, &mem_info, &obj_struct);
4709177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    if (!skip) {
4710177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        lock.unlock();
4711177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        dev_data->dispatch_table.FreeMemory(device, mem, pAllocator);
4712177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        lock.lock();
4713405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (mem != VK_NULL_HANDLE) {
4714405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordFreeMemory(dev_data, mem, mem_info, obj_struct);
4715405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
471674243a735fe102b370237ddf80d3e6f7ec5246dbMark Mueller    }
47175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
47185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4719f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis// Validate that given Map memory range is valid. This means that the memory should not already be mapped,
4720f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis//  and that the size of the map range should be:
4721f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis//  1. Not zero
4722f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis//  2. Within the size of the memory allocation
472351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool ValidateMapMemRange(layer_data *dev_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size) {
472483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
47255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
47265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (size == 0) {
472751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        skip_call = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
472883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                            (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, "MEM",
472983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                            "VkMapMemory: Attempting to map memory range of size zero");
47305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
47315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
473251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto mem_element = dev_data->memObjMap.find(mem);
473351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (mem_element != dev_data->memObjMap.end()) {
473457fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        auto mem_info = mem_element->second.get();
47355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // It is an application error to call VkMapMemory on an object that is already mapped
4736de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        if (mem_info->mem_range.size != 0) {
473751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            skip_call = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
473883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, "MEM",
473983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                "VkMapMemory: Attempting to map memory on an already-mapped object 0x%" PRIxLEAST64, (uint64_t)mem);
47405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
47415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
47425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Validate that offset + size is within object's allocationSize
47435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (size == VK_WHOLE_SIZE) {
4744de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis            if (offset >= mem_info->alloc_info.allocationSize) {
474551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                skip_call =
474651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
474751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                            (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, "MEM",
474851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                            "Mapping Memory from 0x%" PRIx64 " to 0x%" PRIx64
474951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                            " with size of VK_WHOLE_SIZE oversteps total array size 0x%" PRIx64,
475051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                            offset, mem_info->alloc_info.allocationSize, mem_info->alloc_info.allocationSize);
47515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
47525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
4753de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis            if ((offset + size) > mem_info->alloc_info.allocationSize) {
4754f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                skip_call = log_msg(
475551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
4756f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    (uint64_t)mem, __LINE__, VALIDATION_ERROR_00628, "MEM",
4757f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    "Mapping Memory from 0x%" PRIx64 " to 0x%" PRIx64 " oversteps total array size 0x%" PRIx64 ". %s", offset,
4758f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    size + offset, mem_info->alloc_info.allocationSize, validation_error_map[VALIDATION_ERROR_00628]);
47595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
47605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
47615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
476283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
47635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
47645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
476551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void storeMemRanges(layer_data *dev_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size) {
47669a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto mem_info = GetMemObjInfo(dev_data, mem);
476757fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    if (mem_info) {
4768de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        mem_info->mem_range.offset = offset;
4769de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        mem_info->mem_range.size = size;
47705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
47715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
47725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
477351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool deleteMemRanges(layer_data *dev_data, VkDeviceMemory mem) {
477483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
47759a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto mem_info = GetMemObjInfo(dev_data, mem);
477657fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    if (mem_info) {
4777de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        if (!mem_info->mem_range.size) {
47785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Valid Usage: memory must currently be mapped
477951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            skip_call = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
4780f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                                (uint64_t)mem, __LINE__, VALIDATION_ERROR_00649, "MEM",
4781f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                                "Unmapping Memory without memory being mapped: mem obj 0x%" PRIxLEAST64 ". %s", (uint64_t)mem,
4782f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                                validation_error_map[VALIDATION_ERROR_00649]);
47835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
4784de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        mem_info->mem_range.size = 0;
47855f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski        if (mem_info->shadow_copy) {
47865f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            free(mem_info->shadow_copy_base);
47875f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_copy_base = 0;
47885f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_copy = 0;
47895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
47905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
479183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
47925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
47935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
47945f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski// Guard value for pad data
47955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic char NoncoherentMemoryFillValue = 0xb;
47965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
47975f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinskistatic void initializeAndTrackMemory(layer_data *dev_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size,
47985f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                     void **ppData) {
47999a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto mem_info = GetMemObjInfo(dev_data, mem);
480057fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    if (mem_info) {
4801de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        mem_info->p_driver_data = *ppData;
4802de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        uint32_t index = mem_info->alloc_info.memoryTypeIndex;
4803b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis        if (dev_data->phys_dev_mem_props.memoryTypes[index].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) {
48045f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_copy = 0;
48055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
48065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (size == VK_WHOLE_SIZE) {
48075f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                size = mem_info->alloc_info.allocationSize - offset;
48085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
48095f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_pad_size = dev_data->phys_dev_properties.properties.limits.minMemoryMapAlignment;
48105f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            assert(vk_safe_modulo(mem_info->shadow_pad_size,
48115f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                  dev_data->phys_dev_properties.properties.limits.minMemoryMapAlignment) == 0);
48125f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            // Ensure start of mapped region reflects hardware alignment constraints
48135f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            uint64_t map_alignment = dev_data->phys_dev_properties.properties.limits.minMemoryMapAlignment;
48145f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski
48155f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            // From spec: (ppData - offset) must be aligned to at least limits::minMemoryMapAlignment.
48165f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            uint64_t start_offset = offset % map_alignment;
48175f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            // Data passed to driver will be wrapped by a guardband of data to detect over- or under-writes.
4818bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            mem_info->shadow_copy_base =
4819bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                malloc(static_cast<size_t>(2 * mem_info->shadow_pad_size + size + map_alignment + start_offset));
48205f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski
48215f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_copy =
48225f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                reinterpret_cast<char *>((reinterpret_cast<uintptr_t>(mem_info->shadow_copy_base) + map_alignment) &
4823bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         ~(map_alignment - 1)) +
4824bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                start_offset;
48255f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            assert(vk_safe_modulo(reinterpret_cast<uintptr_t>(mem_info->shadow_copy) + mem_info->shadow_pad_size - start_offset,
48265f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                  map_alignment) == 0);
48275f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski
48286e17c244b21ce43ac57404a00a0d844039eed363Mark Lobodzinski            memset(mem_info->shadow_copy, NoncoherentMemoryFillValue, static_cast<size_t>(2 * mem_info->shadow_pad_size + size));
48295f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            *ppData = static_cast<char *>(mem_info->shadow_copy) + mem_info->shadow_pad_size;
48305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
48315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
48325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
48335f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski
4834a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis// Verify that state for fence being waited on is appropriate. That is,
48359867daedbf52debc77d6568162ee21e071699b80Chris Forbes//  a fence being waited on should not already be signaled and
4836a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis//  it should have been submitted on a queue or during acquire next image
483749f6132af865afd5b7f413c91125971ac97c135aChris Forbesstatic inline bool verifyWaitFenceState(layer_data *dev_data, VkFence fence, const char *apiCall) {
483883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
48399b48b44dd917f95b5f34dd629ec4076fc87eb3a2Chris Forbes
48409a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pFence = GetFenceNode(dev_data, fence);
48419b48b44dd917f95b5f34dd629ec4076fc87eb3a2Chris Forbes    if (pFence) {
4842cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes        if (pFence->state == FENCE_UNSIGNALED) {
484383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
484483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 reinterpret_cast<uint64_t &>(fence), __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM",
4845cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "%s called for fence 0x%" PRIxLEAST64
4846cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 " which has not been submitted on a Queue or during "
484783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 "acquire next image.",
484883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                 apiCall, reinterpret_cast<uint64_t &>(fence));
48495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
48505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
485183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
48525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
4853a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis
4854b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlisstatic void RetireFence(layer_data *dev_data, VkFence fence) {
48559a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pFence = GetFenceNode(dev_data, fence);
4856b3ecd4c1fb44a2e65dfc13256afa9150aabde1d4Chris Forbes    if (pFence->signaler.first != VK_NULL_HANDLE) {
485725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Fence signaller is a queue -- use this as proof that prior operations on that queue have completed.
48589a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        RetireWorkOnQueue(dev_data, GetQueueState(dev_data, pFence->signaler.first), pFence->signaler.second);
4859bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    } else {
486025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Fence signaller is the WSI. We're not tracking what the WSI op actually /was/ in CV yet, but we need to mark
486125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // the fence as retired.
4862d4513979120463171eb479cdded9336eb9944da1Chris Forbes        pFence->state = FENCE_RETIRED;
4863d4513979120463171eb479cdded9336eb9944da1Chris Forbes    }
4864b3ecd4c1fb44a2e65dfc13256afa9150aabde1d4Chris Forbes}
4865b3ecd4c1fb44a2e65dfc13256afa9150aabde1d4Chris Forbes
4866accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlisstatic bool PreCallValidateWaitForFences(layer_data *dev_data, uint32_t fence_count, const VkFence *fences) {
4867cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.wait_for_fences) return false;
4868accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    bool skip = false;
4869accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    for (uint32_t i = 0; i < fence_count; i++) {
4870accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis        skip |= verifyWaitFenceState(dev_data, fences[i], "vkWaitForFences");
4871b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis        skip |= VerifyQueueStateToFence(dev_data, fences[i]);
4872accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    }
4873accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    return skip;
4874accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis}
4875accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis
4876b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlisstatic void PostCallRecordWaitForFences(layer_data *dev_data, uint32_t fence_count, const VkFence *fences, VkBool32 wait_all) {
4877b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    // When we know that all fences are complete we can clean/remove their CBs
4878accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    if ((VK_TRUE == wait_all) || (1 == fence_count)) {
4879accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis        for (uint32_t i = 0; i < fence_count; i++) {
4880b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis            RetireFence(dev_data, fences[i]);
4881accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis        }
4882accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    }
4883accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    // NOTE : Alternate case not handled here is when some fences have completed. In
4884accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    //  this case for app to guarantee which fences completed it will have to call
4885b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    //  vkGetFenceStatus() at which point we'll clean/remove their CBs if complete.
4886accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis}
4887accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis
4888bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL WaitForFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences, VkBool32 waitAll,
4889bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                             uint64_t timeout) {
489056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
48915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Verify fence status of submitted fences
4892b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
4893accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    bool skip = PreCallValidateWaitForFences(dev_data, fenceCount, pFences);
4894b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
4895cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
4896a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis
48974a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.WaitForFences(device, fenceCount, pFences, waitAll, timeout);
4898414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller
48995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
4900b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
4901b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis        PostCallRecordWaitForFences(dev_data, fenceCount, pFences, waitAll);
4902b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
49035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
49045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
49055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
49065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4907f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlisstatic bool PreCallValidateGetFenceStatus(layer_data *dev_data, VkFence fence) {
4908cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.get_fence_state) return false;
4909f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis    return verifyWaitFenceState(dev_data, fence, "vkGetFenceStatus");
4910f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis}
4911f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis
4912b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlisstatic void PostCallRecordGetFenceStatus(layer_data *dev_data, VkFence fence) { RetireFence(dev_data, fence); }
4913f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis
491489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL GetFenceStatus(VkDevice device, VkFence fence) {
491556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
4916b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
4917f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis    bool skip = PreCallValidateGetFenceStatus(dev_data, fence);
4918b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
4919cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
4920a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis
49214a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.GetFenceStatus(device, fence);
49225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
4923f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis        lock.lock();
4924b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis        PostCallRecordGetFenceStatus(dev_data, fence);
4925f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis        lock.unlock();
49265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
49275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
49285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
49295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
49303b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlisstatic void PostCallRecordGetDeviceQueue(layer_data *dev_data, uint32_t q_family_index, VkQueue queue) {
49313b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    // Add queue to tracking set only if it is new
49323b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    auto result = dev_data->queues.emplace(queue);
49333b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    if (result.second == true) {
493436c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlis        QUEUE_STATE *queue_state = &dev_data->queueMap[queue];
49353b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis        queue_state->queue = queue;
49363b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis        queue_state->queueFamilyIndex = q_family_index;
49373b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis        queue_state->seq = 0;
49383b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    }
49393b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis}
49403b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis
4941bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL GetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue *pQueue) {
494256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
49434a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.GetDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue);
4944b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::lock_guard<std::mutex> lock(global_lock);
4945b376edacad6f7ab3fcc0a914e9b1673a9fcd5143Mark Lobodzinski
49463b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    PostCallRecordGetDeviceQueue(dev_data, queueFamilyIndex, *pQueue);
49475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
49485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
494936c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic bool PreCallValidateQueueWaitIdle(layer_data *dev_data, VkQueue queue, QUEUE_STATE **queue_state) {
49509a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *queue_state = GetQueueState(dev_data, queue);
4951cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.queue_wait_idle) return false;
4952e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis    return VerifyQueueStateToSeq(dev_data, *queue_state, (*queue_state)->seq + (*queue_state)->submissions.size());
49534273a1c157585a645dca4c960086032793899d05Tobin Ehlis}
49544273a1c157585a645dca4c960086032793899d05Tobin Ehlis
495536c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic void PostCallRecordQueueWaitIdle(layer_data *dev_data, QUEUE_STATE *queue_state) {
4956e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis    RetireWorkOnQueue(dev_data, queue_state, queue_state->seq + queue_state->submissions.size());
49574273a1c157585a645dca4c960086032793899d05Tobin Ehlis}
49584273a1c157585a645dca4c960086032793899d05Tobin Ehlis
495989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL QueueWaitIdle(VkQueue queue) {
496056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
496136c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlis    QUEUE_STATE *queue_state = nullptr;
49629867daedbf52debc77d6568162ee21e071699b80Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
49634273a1c157585a645dca4c960086032793899d05Tobin Ehlis    bool skip = PreCallValidateQueueWaitIdle(dev_data, queue, &queue_state);
49649867daedbf52debc77d6568162ee21e071699b80Chris Forbes    lock.unlock();
4965cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
49664a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.QueueWaitIdle(queue);
49674273a1c157585a645dca4c960086032793899d05Tobin Ehlis    if (VK_SUCCESS == result) {
4968e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis        lock.lock();
4969e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis        PostCallRecordQueueWaitIdle(dev_data, queue_state);
4970e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis        lock.unlock();
49714273a1c157585a645dca4c960086032793899d05Tobin Ehlis    }
49725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
49735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
49745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
49758767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlisstatic bool PreCallValidateDeviceWaitIdle(layer_data *dev_data) {
4976cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.device_wait_idle) return false;
49778767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    bool skip = false;
49788767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    for (auto &queue : dev_data->queueMap) {
49798767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        skip |= VerifyQueueStateToSeq(dev_data, &queue.second, queue.second.seq + queue.second.submissions.size());
49808767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    }
49818767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    return skip;
49828767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis}
49838767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis
49848767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlisstatic void PostCallRecordDeviceWaitIdle(layer_data *dev_data) {
49858767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    for (auto &queue : dev_data->queueMap) {
49868767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        RetireWorkOnQueue(dev_data, &queue.second, queue.second.seq + queue.second.submissions.size());
49878767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    }
49888767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis}
49898767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis
499089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL DeviceWaitIdle(VkDevice device) {
499156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
4992b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
49938767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    bool skip = PreCallValidateDeviceWaitIdle(dev_data);
4994b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
4995cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
49964a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.DeviceWaitIdle(device);
49978767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    if (VK_SUCCESS == result) {
49988767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        lock.lock();
49998767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        PostCallRecordDeviceWaitIdle(dev_data);
50008767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        lock.unlock();
50018767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    }
50025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
50035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
50045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
50051d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlisstatic bool PreCallValidateDestroyFence(layer_data *dev_data, VkFence fence, FENCE_NODE **fence_node, VK_OBJECT *obj_struct) {
50069a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *fence_node = GetFenceNode(dev_data, fence);
50071d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(fence), VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT};
5008cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_fence) return false;
50091d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    bool skip = false;
50101d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    if (*fence_node) {
50111d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        if ((*fence_node)->state == FENCE_INFLIGHT) {
50121d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
5013208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                            (uint64_t)(fence), __LINE__, VALIDATION_ERROR_00173, "DS", "Fence 0x%" PRIx64 " is in use. %s",
5014208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                            (uint64_t)(fence), validation_error_map[VALIDATION_ERROR_00173]);
50151d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        }
50161d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    }
50171d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    return skip;
50181d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis}
50191d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis
50201d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlisstatic void PostCallRecordDestroyFence(layer_data *dev_data, VkFence fence) { dev_data->fenceMap.erase(fence); }
50211d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis
502289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL DestroyFence(VkDevice device, VkFence fence, const VkAllocationCallbacks *pAllocator) {
502356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
50241d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    // Common data objects used pre & post call
50251d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    FENCE_NODE *fence_node = nullptr;
50261d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    VK_OBJECT obj_struct;
5027b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
50281d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    bool skip = PreCallValidateDestroyFence(dev_data, fence, &fence_node, &obj_struct);
50291344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
50301d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    if (!skip) {
50311d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        lock.unlock();
50324a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyFence(device, fence, pAllocator);
50331d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        lock.lock();
50341d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        PostCallRecordDestroyFence(dev_data, fence);
50351d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    }
50365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
50375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5038c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlisstatic bool PreCallValidateDestroySemaphore(layer_data *dev_data, VkSemaphore semaphore, SEMAPHORE_NODE **sema_node,
5039c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis                                            VK_OBJECT *obj_struct) {
50409a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *sema_node = GetSemaphoreNode(dev_data, semaphore);
5041c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(semaphore), VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT};
5042cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_semaphore) return false;
5043c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    bool skip = false;
5044c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    if (*sema_node) {
5045c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *sema_node, *obj_struct, VALIDATION_ERROR_00199);
5046c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    }
5047c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    return skip;
5048c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis}
5049c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis
5050c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlisstatic void PostCallRecordDestroySemaphore(layer_data *dev_data, VkSemaphore sema) { dev_data->semaphoreMap.erase(sema); }
5051c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis
5052bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroySemaphore(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks *pAllocator) {
505356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5054c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    SEMAPHORE_NODE *sema_node;
5055c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    VK_OBJECT obj_struct;
5056e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
5057c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    bool skip = PreCallValidateDestroySemaphore(dev_data, semaphore, &sema_node, &obj_struct);
5058eafbf0b68ee6ea6e0bf33f07e0058d00a96efd9aTobin Ehlis    if (!skip) {
5059eafbf0b68ee6ea6e0bf33f07e0058d00a96efd9aTobin Ehlis        lock.unlock();
50604a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroySemaphore(device, semaphore, pAllocator);
5061c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis        lock.lock();
5062c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis        PostCallRecordDestroySemaphore(dev_data, semaphore);
506399d938c90c2f000ee73fb13513dacf84ffa5651fMark Mueller    }
50645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
50655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
50664710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlisstatic bool PreCallValidateDestroyEvent(layer_data *dev_data, VkEvent event, EVENT_STATE **event_state, VK_OBJECT *obj_struct) {
50679a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *event_state = GetEventNode(dev_data, event);
506894165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(event), VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT};
5069cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_event) return false;
5070d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    bool skip = false;
5071d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    if (*event_state) {
5072d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *event_state, *obj_struct, VALIDATION_ERROR_00213);
5073d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    }
5074d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    return skip;
5075d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis}
5076d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis
50774710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlisstatic void PostCallRecordDestroyEvent(layer_data *dev_data, VkEvent event, EVENT_STATE *event_state, VK_OBJECT obj_struct) {
507839c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, event_state->cb_bindings, obj_struct);
5079d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    dev_data->eventMap.erase(event);
5080d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis}
5081d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis
508289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL DestroyEvent(VkDevice device, VkEvent event, const VkAllocationCallbacks *pAllocator) {
508356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
50844710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis    EVENT_STATE *event_state = nullptr;
5085d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    VK_OBJECT obj_struct;
5086b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5087d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    bool skip = PreCallValidateDestroyEvent(dev_data, event, &event_state, &obj_struct);
5088f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    if (!skip) {
5089f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis        lock.unlock();
50904a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyEvent(device, event, pAllocator);
5091d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis        lock.lock();
5092405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (event != VK_NULL_HANDLE) {
5093405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyEvent(dev_data, event, event_state, obj_struct);
5094405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
5095f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    }
50965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
50975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
509883c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlisstatic bool PreCallValidateDestroyQueryPool(layer_data *dev_data, VkQueryPool query_pool, QUERY_POOL_NODE **qp_state,
509983c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis                                            VK_OBJECT *obj_struct) {
51009a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *qp_state = GetQueryPoolNode(dev_data, query_pool);
510183c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(query_pool), VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT};
5102cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_query_pool) return false;
510383c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    bool skip = false;
510483c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    if (*qp_state) {
510583c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *qp_state, *obj_struct, VALIDATION_ERROR_01012);
510683c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    }
510783c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    return skip;
510883c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis}
510983c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis
5110bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic void PostCallRecordDestroyQueryPool(layer_data *dev_data, VkQueryPool query_pool, QUERY_POOL_NODE *qp_state,
5111bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           VK_OBJECT obj_struct) {
511283c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    invalidateCommandBuffers(dev_data, qp_state->cb_bindings, obj_struct);
511383c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    dev_data->queryPoolMap.erase(query_pool);
511483c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis}
511583c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis
5116bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks *pAllocator) {
511756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
511883c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    QUERY_POOL_NODE *qp_state = nullptr;
511983c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    VK_OBJECT obj_struct;
5120ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
512183c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    bool skip = PreCallValidateDestroyQueryPool(dev_data, queryPool, &qp_state, &obj_struct);
5122f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    if (!skip) {
5123f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis        lock.unlock();
51244a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyQueryPool(device, queryPool, pAllocator);
512583c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis        lock.lock();
5126405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (queryPool != VK_NULL_HANDLE) {
5127405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyQueryPool(dev_data, queryPool, qp_state, obj_struct);
5128405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
5129f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    }
51305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
51319fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlisstatic bool PreCallValidateGetQueryPoolResults(layer_data *dev_data, VkQueryPool query_pool, uint32_t first_query,
51329fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                               uint32_t query_count, VkQueryResultFlags flags,
51339fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                               unordered_map<QueryObject, vector<VkCommandBuffer>> *queries_in_flight) {
51349fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    for (auto cmd_buffer : dev_data->globalInFlightCmdBuffers) {
51359a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto cb = GetCBNode(dev_data, cmd_buffer);
51369fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        for (auto query_state_pair : cb->queryToStateMap) {
51379fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            (*queries_in_flight)[query_state_pair.first].push_back(cmd_buffer);
51385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
51395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5140cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.get_query_pool_results) return false;
51419fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    bool skip = false;
51429fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    for (uint32_t i = 0; i < query_count; ++i) {
51439fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        QueryObject query = {query_pool, first_query + i};
51449fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        auto qif_pair = queries_in_flight->find(query);
51459fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        auto query_state_pair = dev_data->queryToStateMap.find(query);
51469fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        if (query_state_pair != dev_data->queryToStateMap.end()) {
5147ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski            // Available and in flight
51489fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            if (qif_pair != queries_in_flight->end() && query_state_pair != dev_data->queryToStateMap.end() &&
51499fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                query_state_pair->second) {
51509fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                for (auto cmd_buffer : qif_pair->second) {
51519a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto cb = GetCBNode(dev_data, cmd_buffer);
51529fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    auto query_event_pair = cb->waitedEventsBeforeQueryReset.find(query);
51539fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    if (query_event_pair == cb->waitedEventsBeforeQueryReset.end()) {
51549fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
51559fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                        VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
51569fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                        "Cannot get query results on queryPool 0x%" PRIx64 " with index %d which is in flight.",
51579fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                        (uint64_t)(query_pool), first_query + i);
5158ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                    }
5159ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                }
5160ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                // Unavailable and in flight
51619fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            } else if (qif_pair != queries_in_flight->end() && query_state_pair != dev_data->queryToStateMap.end() &&
51629fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                       !query_state_pair->second) {
5163ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                // TODO : Can there be the same query in use by multiple command buffers in flight?
5164ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                bool make_available = false;
51659fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                for (auto cmd_buffer : qif_pair->second) {
51669a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto cb = GetCBNode(dev_data, cmd_buffer);
51679fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    make_available |= cb->queryToStateMap[query];
5168ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                }
5169ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                if (!(((flags & VK_QUERY_RESULT_PARTIAL_BIT) || (flags & VK_QUERY_RESULT_WAIT_BIT)) && make_available)) {
51709fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
51719fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                    VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
51729fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                    "Cannot get query results on queryPool 0x%" PRIx64 " with index %d which is unavailable.",
51739fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                    (uint64_t)(query_pool), first_query + i);
51745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
5175ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                // Unavailable
51769fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            } else if (query_state_pair != dev_data->queryToStateMap.end() && !query_state_pair->second) {
51779fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0,
51789fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
51799fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                "Cannot get query results on queryPool 0x%" PRIx64 " with index %d which is unavailable.",
51809fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                (uint64_t)(query_pool), first_query + i);
51819fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                // Uninitialized
51829fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            } else if (query_state_pair == dev_data->queryToStateMap.end()) {
51839fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0,
51849fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
51859fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                "Cannot get query results on queryPool 0x%" PRIx64
51869fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                " with index %d as data has not been collected for this index.",
51879fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                (uint64_t)(query_pool), first_query + i);
51885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
51895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
51905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
51919fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    return skip;
51929fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis}
51939fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis
51949fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlisstatic void PostCallRecordGetQueryPoolResults(layer_data *dev_data, VkQueryPool query_pool, uint32_t first_query,
51959fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                              uint32_t query_count,
51969fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                              unordered_map<QueryObject, vector<VkCommandBuffer>> *queries_in_flight) {
51979fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    for (uint32_t i = 0; i < query_count; ++i) {
51989fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        QueryObject query = {query_pool, first_query + i};
51999fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        auto qif_pair = queries_in_flight->find(query);
52009fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        auto query_state_pair = dev_data->queryToStateMap.find(query);
52019fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        if (query_state_pair != dev_data->queryToStateMap.end()) {
52029fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            // Available and in flight
52039fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            if (qif_pair != queries_in_flight->end() && query_state_pair != dev_data->queryToStateMap.end() &&
52049fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                query_state_pair->second) {
52059fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                for (auto cmd_buffer : qif_pair->second) {
52069a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto cb = GetCBNode(dev_data, cmd_buffer);
52079fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    auto query_event_pair = cb->waitedEventsBeforeQueryReset.find(query);
52089fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    if (query_event_pair != cb->waitedEventsBeforeQueryReset.end()) {
52099fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                        for (auto event : query_event_pair->second) {
52109fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                            dev_data->eventMap[event].needsSignaled = true;
52119fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                        }
52129fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    }
52139fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                }
52149fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            }
52159fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        }
52169fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    }
52179fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis}
52189fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis
52199fdee42cd357379efb9aa27f90beb75d1f824955Tobin EhlisVKAPI_ATTR VkResult VKAPI_CALL GetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount,
52209fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                                   size_t dataSize, void *pData, VkDeviceSize stride, VkQueryResultFlags flags) {
522156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
52229fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    unordered_map<QueryObject, vector<VkCommandBuffer>> queries_in_flight;
52239fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
52249fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    bool skip = PreCallValidateGetQueryPoolResults(dev_data, queryPool, firstQuery, queryCount, flags, &queries_in_flight);
5225b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
5226cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
52279fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    VkResult result =
52289fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        dev_data->dispatch_table.GetQueryPoolResults(device, queryPool, firstQuery, queryCount, dataSize, pData, stride, flags);
52299fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    lock.lock();
52309fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    PostCallRecordGetQueryPoolResults(dev_data, queryPool, firstQuery, queryCount, &queries_in_flight);
52319fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    lock.unlock();
52329fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    return result;
52335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
52345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5235825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Return true if given ranges intersect, else false
5236825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Prereq : For both ranges, range->end - range->start > 0. This case should have already resulted
5237825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  in an error so not checking that here
5238825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// pad_ranges bool indicates a linear and non-linear comparison which requires padding
5239825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// In the case where padding is required, if an alias is encountered then a validation error is reported and skip_call
5240825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  may be set by the callback function so caller should merge in skip_call value if padding case is possible.
52412ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Stratton// This check can be skipped by passing skip_checks=true, for call sites outside the validation path.
52422ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Strattonstatic bool rangesIntersect(layer_data const *dev_data, MEMORY_RANGE const *range1, MEMORY_RANGE const *range2, bool *skip_call,
52432ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Stratton                            bool skip_checks) {
52447dc3fbb89e2dcf3df8fc2e6639a867a959fef3f3Tobin Ehlis    *skip_call = false;
5245825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto r1_start = range1->start;
5246825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto r1_end = range1->end;
5247825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto r2_start = range2->start;
5248825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto r2_end = range2->end;
5249825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    VkDeviceSize pad_align = 1;
5250825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    if (range1->linear != range2->linear) {
5251825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        pad_align = dev_data->phys_dev_properties.properties.limits.bufferImageGranularity;
5252825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    }
5253cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if ((r1_end & ~(pad_align - 1)) < (r2_start & ~(pad_align - 1))) return false;
5254cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if ((r1_start & ~(pad_align - 1)) > (r2_end & ~(pad_align - 1))) return false;
525547aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
52562ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Stratton    if (!skip_checks && (range1->linear != range2->linear)) {
525753ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis        // In linear vs. non-linear case, warn of aliasing
5258825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        const char *r1_linear_str = range1->linear ? "Linear" : "Non-linear";
5259825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        const char *r1_type_str = range1->image ? "image" : "buffer";
5260825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        const char *r2_linear_str = range2->linear ? "linear" : "non-linear";
5261825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        const char *r2_type_str = range2->image ? "image" : "buffer";
5262825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        auto obj_type = range1->image ? VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT : VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT;
526353ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis        *skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, obj_type, range1->handle, 0,
526453ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis                              MEMTRACK_INVALID_ALIASING, "MEM", "%s %s 0x%" PRIx64 " is aliased with %s %s 0x%" PRIx64
526553ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis                                                                " which may indicate a bug. For further info refer to the "
526653ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis                                                                "Buffer-Image Granularity section of the Vulkan specification. "
526753ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis                                                                "(https://www.khronos.org/registry/vulkan/specs/1.0-extensions/"
526853ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis                                                                "xhtml/vkspec.html#resources-bufferimagegranularity)",
526953ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis                              r1_linear_str, r1_type_str, range1->handle, r2_linear_str, r2_type_str, range2->handle);
527047aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    }
5271825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    // Ranges intersect
5272825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    return true;
527347aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski}
5274623548a271287ae55415e45e3c654ee66d4e79ffTobin Ehlis// Simplified rangesIntersect that calls above function to check range1 for intersection with offset & end addresses
5275c3340a06ecac4d7b9540592cae339f8fc224d0b1Mark Lobodzinskibool rangesIntersect(layer_data const *dev_data, MEMORY_RANGE const *range1, VkDeviceSize offset, VkDeviceSize end) {
5276825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    // Create a local MEMORY_RANGE struct to wrap offset/size
5277825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    MEMORY_RANGE range_wrap;
5278825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    // Synch linear with range1 to avoid padding and potential validation error case
5279825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range_wrap.linear = range1->linear;
5280825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range_wrap.start = offset;
5281cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    range_wrap.end = end;
5282825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    bool tmp_bool;
52832ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Stratton    return rangesIntersect(dev_data, range1, &range_wrap, &tmp_bool, true);
5284825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis}
5285cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis// For given mem_info, set all ranges valid that intersect [offset-end] range
5286cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis// TODO : For ranges where there is no alias, we may want to create new buffer ranges that are valid
5287cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlisstatic void SetMemRangesValid(layer_data const *dev_data, DEVICE_MEM_INFO *mem_info, VkDeviceSize offset, VkDeviceSize end) {
5288cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    bool tmp_bool = false;
5289f6e16b28b808a342cb92768001afa2cfeee08a11Tobin Ehlis    MEMORY_RANGE map_range = {};
5290cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    map_range.linear = true;
5291cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    map_range.start = offset;
5292cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    map_range.end = end;
5293cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    for (auto &handle_range_pair : mem_info->bound_ranges) {
52942ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Stratton        if (rangesIntersect(dev_data, &handle_range_pair.second, &map_range, &tmp_bool, false)) {
5295cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis            // TODO : WARN here if tmp_bool true?
5296cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis            handle_range_pair.second.valid = true;
5297cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis        }
5298cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    }
5299cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis}
53000ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
53010ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Strattonstatic bool ValidateInsertMemoryRange(layer_data const *dev_data, uint64_t handle, DEVICE_MEM_INFO *mem_info,
53020ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                      VkDeviceSize memoryOffset, VkMemoryRequirements memRequirements, bool is_image,
53030ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                      bool is_linear, const char *api_name) {
53040ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    bool skip = false;
53050ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
53060ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    MEMORY_RANGE range;
53070ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.image = is_image;
53080ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.handle = handle;
53090ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.linear = is_linear;
53100ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.valid = mem_info->global_valid;
53110ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.memory = mem_info->mem;
53120ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.start = memoryOffset;
53130ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.size = memRequirements.size;
53140ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.end = memoryOffset + memRequirements.size - 1;
53150ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.aliases.clear();
53160ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
53170ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    // Check for aliasing problems.
53180ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    for (auto &obj_range_pair : mem_info->bound_ranges) {
53190ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        auto check_range = &obj_range_pair.second;
53200ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        bool intersection_error = false;
53212ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Stratton        if (rangesIntersect(dev_data, &range, check_range, &intersection_error, false)) {
53220ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton            skip |= intersection_error;
53230ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton            range.aliases.insert(check_range);
53240ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        }
53250ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    }
53260ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
53270ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    if (memoryOffset >= mem_info->alloc_info.allocationSize) {
53280ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        UNIQUE_VALIDATION_ERROR_CODE error_code = is_image ? VALIDATION_ERROR_00805 : VALIDATION_ERROR_00793;
53290ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
53300ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                       reinterpret_cast<uint64_t &>(mem_info->mem), __LINE__, error_code, "MEM",
53310ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                       "In %s, attempting to bind memory (0x%" PRIxLEAST64 ") to object (0x%" PRIxLEAST64
53320ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                       "), memoryOffset=0x%" PRIxLEAST64 " must be less than the memory allocation size 0x%" PRIxLEAST64 ". %s",
53330ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                       api_name, reinterpret_cast<uint64_t &>(mem_info->mem), handle, memoryOffset,
53340ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                       mem_info->alloc_info.allocationSize, validation_error_map[error_code]);
53350ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    }
53360ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
53370ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    return skip;
53380ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton}
53390ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
5340825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Object with given handle is being bound to memory w/ given mem_info struct.
5341825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  Track the newly bound memory range with given memoryOffset
5342825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  Also scan any previous ranges, track aliased ranges with new range, and flag an error if a linear
5343825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  and non-linear range incorrectly overlap.
5344825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Return true if an error is flagged and the user callback returns "true", otherwise false
5345825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// is_image indicates an image object, otherwise handle is for a buffer
5346825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// is_linear indicates a buffer or linear image
53470ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Strattonstatic void InsertMemoryRange(layer_data const *dev_data, uint64_t handle, DEVICE_MEM_INFO *mem_info, VkDeviceSize memoryOffset,
53480ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                              VkMemoryRequirements memRequirements, bool is_image, bool is_linear) {
53495360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    MEMORY_RANGE range;
5350825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
5351825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range.image = is_image;
535247aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    range.handle = handle;
5353825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range.linear = is_linear;
5354f541bf53dee6daf82a4c8304354eac599a884d29Tobin Ehlis    range.valid = mem_info->global_valid;
5355825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range.memory = mem_info->mem;
535647aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    range.start = memoryOffset;
5357825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range.size = memRequirements.size;
535847aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    range.end = memoryOffset + memRequirements.size - 1;
53595360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    range.aliases.clear();
53605360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    // Update Memory aliasing
536175f4c8cec0996021a4258b9bf920a9e0fea4eac1Tobin 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
53625360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    // inserted into map before loop to get the final ptr, then we may enter loop when not needed & we check range against itself
53635360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    std::unordered_set<MEMORY_RANGE *> tmp_alias_ranges;
5364825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    for (auto &obj_range_pair : mem_info->bound_ranges) {
5365825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        auto check_range = &obj_range_pair.second;
53665360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis        bool intersection_error = false;
53672ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Stratton        if (rangesIntersect(dev_data, &range, check_range, &intersection_error, true)) {
5368825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis            range.aliases.insert(check_range);
53695360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis            tmp_alias_ranges.insert(check_range);
5370825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        }
5371825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    }
53725360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    mem_info->bound_ranges[handle] = std::move(range);
53735360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    for (auto tmp_range : tmp_alias_ranges) {
53745360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis        tmp_range->aliases.insert(&mem_info->bound_ranges[handle]);
53755360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    }
5376825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    if (is_image)
5377825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        mem_info->bound_images.insert(handle);
5378825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    else
5379825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        mem_info->bound_buffers.insert(handle);
538047aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski}
538147aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
53820ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Strattonstatic bool ValidateInsertImageMemoryRange(layer_data const *dev_data, VkImage image, DEVICE_MEM_INFO *mem_info,
53830ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                           VkDeviceSize mem_offset, VkMemoryRequirements mem_reqs, bool is_linear,
53840ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                           const char *api_name) {
53850ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    return ValidateInsertMemoryRange(dev_data, reinterpret_cast<uint64_t &>(image), mem_info, mem_offset, mem_reqs, true, is_linear,
53860ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                     api_name);
53870ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton}
53880ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Strattonstatic void InsertImageMemoryRange(layer_data const *dev_data, VkImage image, DEVICE_MEM_INFO *mem_info, VkDeviceSize mem_offset,
53890ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                   VkMemoryRequirements mem_reqs, bool is_linear) {
53900ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    InsertMemoryRange(dev_data, reinterpret_cast<uint64_t &>(image), mem_info, mem_offset, mem_reqs, true, is_linear);
5391825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis}
5392825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
53930ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Strattonstatic bool ValidateInsertBufferMemoryRange(layer_data const *dev_data, VkBuffer buffer, DEVICE_MEM_INFO *mem_info,
53940ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                            VkDeviceSize mem_offset, VkMemoryRequirements mem_reqs, const char *api_name) {
53950ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    return ValidateInsertMemoryRange(dev_data, reinterpret_cast<uint64_t &>(buffer), mem_info, mem_offset, mem_reqs, false, true,
53960ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                     api_name);
53970ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton}
53980ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Strattonstatic void InsertBufferMemoryRange(layer_data const *dev_data, VkBuffer buffer, DEVICE_MEM_INFO *mem_info, VkDeviceSize mem_offset,
53990ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                    VkMemoryRequirements mem_reqs) {
54000ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    InsertMemoryRange(dev_data, reinterpret_cast<uint64_t &>(buffer), mem_info, mem_offset, mem_reqs, false, true);
5401825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis}
5402825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
5403825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Remove MEMORY_RANGE struct for give handle from bound_ranges of mem_info
5404825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  is_image indicates if handle is for image or buffer
5405825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  This function will also remove the handle-to-index mapping from the appropriate
5406825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  map and clean up any aliases for range being removed.
5407825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlisstatic void RemoveMemoryRange(uint64_t handle, DEVICE_MEM_INFO *mem_info, bool is_image) {
5408825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto erase_range = &mem_info->bound_ranges[handle];
5409825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    for (auto alias_range : erase_range->aliases) {
5410825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        alias_range->aliases.erase(erase_range);
541147aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    }
54125360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    erase_range->aliases.clear();
5413825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    mem_info->bound_ranges.erase(handle);
54141cba4e1b5940c6818572e05dcad5a3a47fafbc9eTobin Ehlis    if (is_image) {
5415825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        mem_info->bound_images.erase(handle);
54161cba4e1b5940c6818572e05dcad5a3a47fafbc9eTobin Ehlis    } else {
5417825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        mem_info->bound_buffers.erase(handle);
54181cba4e1b5940c6818572e05dcad5a3a47fafbc9eTobin Ehlis    }
541947aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski}
542047aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
5421842b2d28ded1c6e2c38491a81213d0e1d1b7295aMark Lobodzinskivoid RemoveBufferMemoryRange(uint64_t handle, DEVICE_MEM_INFO *mem_info) { RemoveMemoryRange(handle, mem_info, false); }
5422825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
54238c59133586421be878d393799b30044497f77727Mark Lobodzinskivoid RemoveImageMemoryRange(uint64_t handle, DEVICE_MEM_INFO *mem_info) { RemoveMemoryRange(handle, mem_info, true); }
5424825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
5425bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator) {
542656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5427e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    BUFFER_STATE *buffer_state = nullptr;
5428e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    VK_OBJECT obj_struct;
5429b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5430e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    bool skip = PreCallValidateDestroyBuffer(dev_data, buffer, &buffer_state, &obj_struct);
5431e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    if (!skip) {
5432b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
54334a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyBuffer(device, buffer, pAllocator);
5434e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis        lock.lock();
5435405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (buffer != VK_NULL_HANDLE) {
5436405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyBuffer(dev_data, buffer, buffer_state, obj_struct);
5437405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
543847aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    }
54395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
54405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5441bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyBufferView(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks *pAllocator) {
544256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5443f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    // Common data objects used pre & post call
54448e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    BUFFER_VIEW_STATE *buffer_view_state = nullptr;
54458e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    VK_OBJECT obj_struct;
5446a123662876eebfa844faa65ae3f071d3d77618ebTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
54478e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    // Validate state before calling down chain, update common data if we'll be calling down chain
54488e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    bool skip = PreCallValidateDestroyBufferView(dev_data, bufferView, &buffer_view_state, &obj_struct);
544938e26abbaa884eb48bfec4ddb4e0ae2c90634e06Tobin Ehlis    if (!skip) {
545038e26abbaa884eb48bfec4ddb4e0ae2c90634e06Tobin Ehlis        lock.unlock();
54514a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyBufferView(device, bufferView, pAllocator);
54528e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis        lock.lock();
5453405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (bufferView != VK_NULL_HANDLE) {
5454405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyBufferView(dev_data, bufferView, buffer_view_state, obj_struct);
5455405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
54565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
54575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
54585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
54592a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin EhlisVKAPI_ATTR void VKAPI_CALL DestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) {
546056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
54611facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    IMAGE_STATE *image_state = nullptr;
54622a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    VK_OBJECT obj_struct;
54632a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
54642a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    bool skip = PreCallValidateDestroyImage(dev_data, image, &image_state, &obj_struct);
54652a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    if (!skip) {
5466f940225c9e5e3e14b3f5a32d3ea360b585614600Tobin Ehlis        lock.unlock();
54674a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyImage(device, image, pAllocator);
54682a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis        lock.lock();
5469405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (image != VK_NULL_HANDLE) {
5470405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyImage(dev_data, image, image_state, obj_struct);
5471405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
54725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
54735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
54745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
54754261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinskistatic bool ValidateMemoryTypes(const layer_data *dev_data, const DEVICE_MEM_INFO *mem_info, const uint32_t memory_type_bits,
5476f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                                const char *funcName, UNIQUE_VALIDATION_ERROR_CODE msgCode) {
54774261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinski    bool skip_call = false;
5478de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis    if (((1 << mem_info->alloc_info.memoryTypeIndex) & memory_type_bits) == 0) {
5479f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen        skip_call =
5480f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
5481f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    reinterpret_cast<const uint64_t &>(mem_info->mem), __LINE__, msgCode, "MT",
5482f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    "%s(): MemoryRequirements->memoryTypeBits (0x%X) for this object type are not compatible with the memory "
5483f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    "type (0x%X) of this memory object 0x%" PRIx64 ". %s",
5484f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    funcName, memory_type_bits, mem_info->alloc_info.memoryTypeIndex,
5485f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    reinterpret_cast<const uint64_t &>(mem_info->mem), validation_error_map[msgCode]);
54864261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinski    }
54874261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinski    return skip_call;
54884261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinski}
54894261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinski
5490160335c453ec51cc48bdef78e8befdb3c86ff292Cort Strattonstatic bool PreCallValidateBindBufferMemory(layer_data *dev_data, VkBuffer buffer, BUFFER_STATE *buffer_state, VkDeviceMemory mem,
5491160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                                            VkDeviceSize memoryOffset) {
54929207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    bool skip = false;
54935cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (buffer_state) {
5494160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        std::unique_lock<std::mutex> lock(global_lock);
54959207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        // Track objects tied to memory
54969207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        uint64_t buffer_handle = reinterpret_cast<uint64_t &>(buffer);
5497c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        skip = ValidateSetMemBinding(dev_data, mem, buffer_handle, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, "vkBindBufferMemory()");
54982eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        if (!buffer_state->memory_requirements_checked) {
54992eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            // There's not an explicit requirement in the spec to call vkGetBufferMemoryRequirements() prior to calling
55009207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton            // BindBufferMemory, but it's implied in that memory being bound must conform with VkMemoryRequirements from
55019207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton            // vkGetBufferMemoryRequirements()
55029207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
55039207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            buffer_handle, __LINE__, DRAWSTATE_INVALID_BUFFER, "DS",
55049207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            "vkBindBufferMemory(): Binding memory to buffer 0x%" PRIxLEAST64
55059207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            " but vkGetBufferMemoryRequirements() has not been called on that buffer.",
55069207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            buffer_handle);
55072eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            // Make the call for them so we can verify the state
55082eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            lock.unlock();
55099207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton            dev_data->dispatch_table.GetBufferMemoryRequirements(dev_data->device, buffer, &buffer_state->requirements);
55102eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            lock.lock();
55112eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        }
551247aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
55130ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        // Validate bound memory range information
55149a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto mem_info = GetMemObjInfo(dev_data, mem);
551557fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        if (mem_info) {
55160ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton            skip |= ValidateInsertBufferMemoryRange(dev_data, buffer, mem_info, memoryOffset, buffer_state->requirements,
55170ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                                    "vkBindBufferMemory()");
55189207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton            skip |= ValidateMemoryTypes(dev_data, mem_info, buffer_state->requirements.memoryTypeBits, "vkBindBufferMemory()",
55199207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                                        VALIDATION_ERROR_00797);
552047aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski        }
552147aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
55222c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves        // Validate memory requirements alignment
55232eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        if (vk_safe_modulo(memoryOffset, buffer_state->requirements.alignment) != 0) {
5524f60e41965223825191505eebc96491bb52e494a2Cort Stratton            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
5525f60e41965223825191505eebc96491bb52e494a2Cort Stratton                            buffer_handle, __LINE__, VALIDATION_ERROR_02174, "DS",
55269207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            "vkBindBufferMemory(): memoryOffset is 0x%" PRIxLEAST64
55279207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            " but must be an integer multiple of the "
55289207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            "VkMemoryRequirements::alignment value 0x%" PRIxLEAST64
55299207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            ", returned from a call to vkGetBufferMemoryRequirements with buffer. %s",
55309207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            memoryOffset, buffer_state->requirements.alignment, validation_error_map[VALIDATION_ERROR_02174]);
55312c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves        }
5532ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller
5533160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        // Validate memory requirements size
5534160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        if (buffer_state->requirements.size > (mem_info->alloc_info.allocationSize - memoryOffset)) {
5535160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
5536160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            buffer_handle, __LINE__, VALIDATION_ERROR_02175, "DS",
5537160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            "vkBindBufferMemory(): memory size minus memoryOffset is 0x%" PRIxLEAST64
5538160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            " but must be at least as large as "
5539160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            "VkMemoryRequirements::size value 0x%" PRIxLEAST64
5540160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            ", returned from a call to vkGetBufferMemoryRequirements with buffer. %s",
5541160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            mem_info->alloc_info.allocationSize - memoryOffset, buffer_state->requirements.size,
5542160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            validation_error_map[VALIDATION_ERROR_02175]);
5543160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        }
5544160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton
55452c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves        // Validate device limits alignments
5546ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller        static const VkBufferUsageFlagBits usage_list[3] = {
5547ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller            static_cast<VkBufferUsageFlagBits>(VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT),
5548bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT};
5549bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        static const char *memory_type[3] = {"texel", "uniform", "storage"};
5550bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        static const char *offset_name[3] = {"minTexelBufferOffsetAlignment", "minUniformBufferOffsetAlignment",
5551bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                             "minStorageBufferOffsetAlignment"};
5552cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski
55539207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        // TODO:  vk_validation_stats.py cannot abide braces immediately preceding or following a validation error enum
5554cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        // clang-format off
55550ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        static const UNIQUE_VALIDATION_ERROR_CODE msgCode[3] = { VALIDATION_ERROR_00794, VALIDATION_ERROR_00795,
55560ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton            VALIDATION_ERROR_00796 };
5557cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        // clang-format on
5558ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller
5559ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller        // Keep this one fresh!
5560ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller        const VkDeviceSize offset_requirement[3] = {
5561ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller            dev_data->phys_dev_properties.properties.limits.minTexelBufferOffsetAlignment,
5562ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller            dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment,
5563bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            dev_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment};
55648718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis        VkBufferUsageFlags usage = dev_data->bufferMap[buffer].get()->createInfo.usage;
5565ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller
5566ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller        for (int i = 0; i < 3; i++) {
5567ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller            if (usage & usage_list[i]) {
5568ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller                if (vk_safe_modulo(memoryOffset, offset_requirement[i]) != 0) {
55699207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                    skip |= log_msg(
5570f60e41965223825191505eebc96491bb52e494a2Cort Stratton                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, buffer_handle,
5571cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        __LINE__, msgCode[i], "DS", "vkBindBufferMemory(): %s memoryOffset is 0x%" PRIxLEAST64
5572cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                    " but must be a multiple of "
5573cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                    "device limit %s 0x%" PRIxLEAST64 ". %s",
5574cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        memory_type[i], memoryOffset, offset_name[i], offset_requirement[i], validation_error_map[msgCode[i]]);
5575ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller                }
55762c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves            }
55772c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves        }
55785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
55799207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    return skip;
55809207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton}
55819207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton
5582160335c453ec51cc48bdef78e8befdb3c86ff292Cort Strattonstatic void PostCallRecordBindBufferMemory(layer_data *dev_data, VkBuffer buffer, BUFFER_STATE *buffer_state, VkDeviceMemory mem,
5583160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                                           VkDeviceSize memoryOffset) {
55849207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    if (buffer_state) {
5585160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        std::unique_lock<std::mutex> lock(global_lock);
55860ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        // Track bound memory range information
55870ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        auto mem_info = GetMemObjInfo(dev_data, mem);
55880ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        if (mem_info) {
55890ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton            InsertBufferMemoryRange(dev_data, buffer, mem_info, memoryOffset, buffer_state->requirements);
55900ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        }
55910ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
5592c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        // Track objects tied to memory
5593c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        uint64_t buffer_handle = reinterpret_cast<uint64_t &>(buffer);
5594c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        SetMemBinding(dev_data, mem, buffer_handle, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, "vkBindBufferMemory()");
5595c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton
55969207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        buffer_state->binding.mem = mem;
55979207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        buffer_state->binding.offset = memoryOffset;
55989207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        buffer_state->binding.size = buffer_state->requirements.size;
55999207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    }
56009207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton}
56019207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton
56029207132ef623d47fcbdfeb9ebc796eade35a2f4cCort StrattonVKAPI_ATTR VkResult VKAPI_CALL BindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
56039207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
56049207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
5605160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton    auto buffer_state = GetBufferState(dev_data, buffer);
5606160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton    bool skip = PreCallValidateBindBufferMemory(dev_data, buffer, buffer_state, mem, memoryOffset);
56079207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    if (!skip) {
56084a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.BindBufferMemory(device, buffer, mem, memoryOffset);
56099207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        if (result == VK_SUCCESS) {
5610160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton            PostCallRecordBindBufferMemory(dev_data, buffer, buffer_state, mem, memoryOffset);
56119207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        }
56125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
56135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
56145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
56155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5616bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL GetBufferMemoryRequirements(VkDevice device, VkBuffer buffer,
5617bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                       VkMemoryRequirements *pMemoryRequirements) {
561856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
561915caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    dev_data->dispatch_table.GetBufferMemoryRequirements(device, buffer, pMemoryRequirements);
56209a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto buffer_state = GetBufferState(dev_data, buffer);
562115caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    if (buffer_state) {
562215caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis        buffer_state->requirements = *pMemoryRequirements;
56232eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        buffer_state->memory_requirements_checked = true;
562415caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    }
56255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
56265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5627bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL GetImageMemoryRequirements(VkDevice device, VkImage image, VkMemoryRequirements *pMemoryRequirements) {
562856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
562915caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    dev_data->dispatch_table.GetImageMemoryRequirements(device, image, pMemoryRequirements);
56309a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto image_state = GetImageState(dev_data, image);
563115caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    if (image_state) {
563215caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis        image_state->requirements = *pMemoryRequirements;
56332eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        image_state->memory_requirements_checked = true;
563415caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    }
56355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
5636593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
5637bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyImageView(VkDevice device, VkImageView imageView, const VkAllocationCallbacks *pAllocator) {
563856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5639f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    // Common data objects used pre & post call
5640f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    IMAGE_VIEW_STATE *image_view_state = nullptr;
5641f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    VK_OBJECT obj_struct;
5642a123662876eebfa844faa65ae3f071d3d77618ebTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
5643f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    bool skip = PreCallValidateDestroyImageView(dev_data, imageView, &image_view_state, &obj_struct);
5644d85c42a6c1d6ad7a6f684c5bd793aab482b7705cTobin Ehlis    if (!skip) {
5645d85c42a6c1d6ad7a6f684c5bd793aab482b7705cTobin Ehlis        lock.unlock();
56464a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyImageView(device, imageView, pAllocator);
5647f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis        lock.lock();
5648405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (imageView != VK_NULL_HANDLE) {
5649405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyImageView(dev_data, imageView, image_view_state, obj_struct);
5650405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
5651d85c42a6c1d6ad7a6f684c5bd793aab482b7705cTobin Ehlis    }
56525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
56535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5654bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyShaderModule(VkDevice device, VkShaderModule shaderModule,
5655bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                               const VkAllocationCallbacks *pAllocator) {
565656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5657918c283ac4f8c604b79abd0c8b5706d2a7352a34Chris Forbes
5658b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
565951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    dev_data->shaderModuleMap.erase(shaderModule);
5660b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
5661918c283ac4f8c604b79abd0c8b5706d2a7352a34Chris Forbes
566251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    dev_data->dispatch_table.DestroyShaderModule(device, shaderModule, pAllocator);
56635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
56645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
56654c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic bool PreCallValidateDestroyPipeline(layer_data *dev_data, VkPipeline pipeline, PIPELINE_STATE **pipeline_state,
56668bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis                                           VK_OBJECT *obj_struct) {
566794165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *pipeline_state = getPipelineState(dev_data, pipeline);
566894165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(pipeline), VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT};
5669cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_pipeline) return false;
56708bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    bool skip = false;
56718bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    if (*pipeline_state) {
56721803032f91d772ff3589c9f5a51ade5b299ba538Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *pipeline_state, *obj_struct, VALIDATION_ERROR_00555);
56738bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    }
56748bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    return skip;
56758bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis}
56768bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis
56774c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic void PostCallRecordDestroyPipeline(layer_data *dev_data, VkPipeline pipeline, PIPELINE_STATE *pipeline_state,
56788bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis                                          VK_OBJECT obj_struct) {
56798bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    // Any bound cmd buffers are now invalid
568039c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, pipeline_state->cb_bindings, obj_struct);
56818bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    dev_data->pipelineMap.erase(pipeline);
56828bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis}
56838bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis
5684bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyPipeline(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks *pAllocator) {
568556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
56864c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    PIPELINE_STATE *pipeline_state = nullptr;
56878bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    VK_OBJECT obj_struct;
5688e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
56898bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    bool skip = PreCallValidateDestroyPipeline(dev_data, pipeline, &pipeline_state, &obj_struct);
5690f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    if (!skip) {
5691f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis        lock.unlock();
56924a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyPipeline(device, pipeline, pAllocator);
56938bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis        lock.lock();
5694405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (pipeline != VK_NULL_HANDLE) {
5695405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyPipeline(dev_data, pipeline, pipeline_state, obj_struct);
5696405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
5697f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    }
56985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
56995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5700bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyPipelineLayout(VkDevice device, VkPipelineLayout pipelineLayout,
5701bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkAllocationCallbacks *pAllocator) {
570256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5703e28cddb35c63274c13873b9a7060ad43b255c6f1Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
57046792ea7cc0ce5fa64b7bd6c946460608cbda91c7Tobin Ehlis    dev_data->pipelineLayoutMap.erase(pipelineLayout);
5705e28cddb35c63274c13873b9a7060ad43b255c6f1Tobin Ehlis    lock.unlock();
5706e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis
57074a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.DestroyPipelineLayout(device, pipelineLayout, pAllocator);
57085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
57095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5710d31a44af6da568692a73201825459689c9431867Tobin Ehlisstatic bool PreCallValidateDestroySampler(layer_data *dev_data, VkSampler sampler, SAMPLER_STATE **sampler_state,
5711806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis                                          VK_OBJECT *obj_struct) {
57129a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *sampler_state = GetSamplerState(dev_data, sampler);
571394165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(sampler), VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT};
5714cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_sampler) return false;
5715806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    bool skip = false;
5716806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    if (*sampler_state) {
5717806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *sampler_state, *obj_struct, VALIDATION_ERROR_00837);
5718806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    }
5719806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    return skip;
5720806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis}
5721806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis
5722d31a44af6da568692a73201825459689c9431867Tobin Ehlisstatic void PostCallRecordDestroySampler(layer_data *dev_data, VkSampler sampler, SAMPLER_STATE *sampler_state,
5723806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis                                         VK_OBJECT obj_struct) {
5724806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    // Any bound cmd buffers are now invalid
5725cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (sampler_state) invalidateCommandBuffers(dev_data, sampler_state->cb_bindings, obj_struct);
5726806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    dev_data->samplerMap.erase(sampler);
5727806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis}
5728806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis
5729bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroySampler(VkDevice device, VkSampler sampler, const VkAllocationCallbacks *pAllocator) {
573056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5731d31a44af6da568692a73201825459689c9431867Tobin Ehlis    SAMPLER_STATE *sampler_state = nullptr;
5732806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    VK_OBJECT obj_struct;
573356f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
5734806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    bool skip = PreCallValidateDestroySampler(dev_data, sampler, &sampler_state, &obj_struct);
5735f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    if (!skip) {
5736f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis        lock.unlock();
57374a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroySampler(device, sampler, pAllocator);
5738806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis        lock.lock();
5739405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (sampler != VK_NULL_HANDLE) {
5740405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroySampler(dev_data, sampler, sampler_state, obj_struct);
5741405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
5742f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    }
57435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
57445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
574579c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlisstatic void PostCallRecordDestroyDescriptorSetLayout(layer_data *dev_data, VkDescriptorSetLayout ds_layout) {
574679c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis    dev_data->descriptorSetLayoutMap.erase(ds_layout);
574779c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis}
574879c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis
5749bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyDescriptorSetLayout(VkDevice device, VkDescriptorSetLayout descriptorSetLayout,
5750bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      const VkAllocationCallbacks *pAllocator) {
575156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
575279c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis    dev_data->dispatch_table.DestroyDescriptorSetLayout(device, descriptorSetLayout, pAllocator);
575379c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
575479c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis    PostCallRecordDestroyDescriptorSetLayout(dev_data, descriptorSetLayout);
57555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
57565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5757c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlisstatic bool PreCallValidateDestroyDescriptorPool(layer_data *dev_data, VkDescriptorPool pool,
5758a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis                                                 DESCRIPTOR_POOL_STATE **desc_pool_state, VK_OBJECT *obj_struct) {
57599a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *desc_pool_state = GetDescriptorPoolState(dev_data, pool);
576094165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(pool), VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT};
5761cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_descriptor_pool) return false;
5762c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    bool skip = false;
5763c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    if (*desc_pool_state) {
57641803032f91d772ff3589c9f5a51ade5b299ba538Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *desc_pool_state, *obj_struct, VALIDATION_ERROR_00901);
5765c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    }
5766c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    return skip;
5767c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis}
5768c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis
5769c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlisstatic void PostCallRecordDestroyDescriptorPool(layer_data *dev_data, VkDescriptorPool descriptorPool,
5770a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis                                                DESCRIPTOR_POOL_STATE *desc_pool_state, VK_OBJECT obj_struct) {
5771c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    // Any bound cmd buffers are now invalid
577239c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, desc_pool_state->cb_bindings, obj_struct);
5773c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    // Free sets that were in this pool
5774c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    for (auto ds : desc_pool_state->sets) {
5775c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis        freeDescriptorSet(dev_data, ds);
5776c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    }
5777c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    dev_data->descriptorPoolMap.erase(descriptorPool);
5778c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis}
5779c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis
5780bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool,
5781bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkAllocationCallbacks *pAllocator) {
578256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5783a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis    DESCRIPTOR_POOL_STATE *desc_pool_state = nullptr;
5784c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    VK_OBJECT obj_struct;
5785c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
5786c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    bool skip = PreCallValidateDestroyDescriptorPool(dev_data, descriptorPool, &desc_pool_state, &obj_struct);
5787c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    if (!skip) {
5788c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis        lock.unlock();
5789c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis        dev_data->dispatch_table.DestroyDescriptorPool(device, descriptorPool, pAllocator);
5790c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis        lock.lock();
5791405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (descriptorPool != VK_NULL_HANDLE) {
5792405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyDescriptorPool(dev_data, descriptorPool, desc_pool_state, obj_struct);
5793405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
5794c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    }
57955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
5796bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis// Verify cmdBuffer in given cb_node is not in global in-flight set, and return skip_call result
5797bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis//  If this is a secondary command buffer, then make sure its primary is also in-flight
5798bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis//  If primary is not in-flight, then remove secondary from global in-flight set
5799bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis// This function is only valid at a point when cmdBuffer is being reset or freed
5800cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlisstatic bool checkCommandBufferInFlight(layer_data *dev_data, const GLOBAL_CB_NODE *cb_node, const char *action,
5801cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis                                       UNIQUE_VALIDATION_ERROR_CODE error_code) {
5802bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    bool skip_call = false;
5803bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    if (dev_data->globalInFlightCmdBuffers.count(cb_node->commandBuffer)) {
5804bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        // Primary CB or secondary where primary is also in-flight is an error
5805bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        if ((cb_node->createInfo.level != VK_COMMAND_BUFFER_LEVEL_SECONDARY) ||
5806bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis            (dev_data->globalInFlightCmdBuffers.count(cb_node->primaryCommandBuffer))) {
5807cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis            skip_call |=
5808cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
5809cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis                        reinterpret_cast<const uint64_t &>(cb_node->commandBuffer), __LINE__, error_code, "DS",
5810226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "Attempt to %s command buffer (0x%p) which is in use. %s", action, cb_node->commandBuffer,
5811226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        validation_error_map[error_code]);
5812bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        }
5813bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    }
5814bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    return skip_call;
5815bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis}
5816a964cad279f9749cd9ebfc7555247ff3bff26d53Chris Forbes
5817bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis// Iterate over all cmdBuffers in given commandPool and verify that each is not in use
5818cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlisstatic bool checkCommandBuffersInFlight(layer_data *dev_data, COMMAND_POOL_NODE *pPool, const char *action,
5819cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis                                        UNIQUE_VALIDATION_ERROR_CODE error_code) {
5820bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    bool skip_call = false;
5821a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes    for (auto cmd_buffer : pPool->commandBuffers) {
5822a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes        if (dev_data->globalInFlightCmdBuffers.count(cmd_buffer)) {
58239a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            skip_call |= checkCommandBufferInFlight(dev_data, GetCBNode(dev_data, cmd_buffer), action, error_code);
5824bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        }
5825bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    }
5826bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    return skip_call;
5827bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis}
58285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5829a01b5eb150981aad061238e64b173d0da8c11140Chris Forbesstatic void clearCommandBuffersInFlight(layer_data *dev_data, COMMAND_POOL_NODE *pPool) {
5830a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes    for (auto cmd_buffer : pPool->commandBuffers) {
5831a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes        dev_data->globalInFlightCmdBuffers.erase(cmd_buffer);
5832a964cad279f9749cd9ebfc7555247ff3bff26d53Chris Forbes    }
5833a964cad279f9749cd9ebfc7555247ff3bff26d53Chris Forbes}
5834a964cad279f9749cd9ebfc7555247ff3bff26d53Chris Forbes
5835bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL FreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount,
5836bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              const VkCommandBuffer *pCommandBuffers) {
583756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
58385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool skip_call = false;
5839b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5840c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes
58415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < commandBufferCount; i++) {
58429a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto cb_node = GetCBNode(dev_data, pCommandBuffers[i]);
58435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Delete CB information structure, and remove from commandBufferMap
58449f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        if (cb_node) {
5845cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis            skip_call |= checkCommandBufferInFlight(dev_data, cb_node, "free", VALIDATION_ERROR_00096);
5846c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes        }
5847c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes    }
5848c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes
5849cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return;
5850c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes
58519a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pPool = GetCommandPoolNode(dev_data, commandPool);
5852c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes    for (uint32_t i = 0; i < commandBufferCount; i++) {
58539a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto cb_node = GetCBNode(dev_data, pCommandBuffers[i]);
5854c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes        // Delete CB information structure, and remove from commandBufferMap
58559f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        if (cb_node) {
58569f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis            dev_data->globalInFlightCmdBuffers.erase(cb_node->commandBuffer);
58575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // reset prior to delete for data clean-up
58589f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis            resetCB(dev_data, cb_node->commandBuffer);
58599f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis            dev_data->commandBufferMap.erase(cb_node->commandBuffer);
58609f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis            delete cb_node;
58615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
58625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
58635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Remove commandBuffer reference from commandPoolMap
5864c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes        pPool->commandBuffers.remove(pCommandBuffers[i]);
58655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5866b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
5867e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis
58684a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.FreeCommandBuffers(device, commandPool, commandBufferCount, pCommandBuffers);
58695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
58705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
587189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo *pCreateInfo,
5872bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkAllocationCallbacks *pAllocator, VkCommandPool *pCommandPool) {
587356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
58745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
58754a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateCommandPool(device, pCreateInfo, pAllocator, pCommandPool);
58765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
58775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
5878b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
58795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->commandPoolMap[*pCommandPool].createFlags = pCreateInfo->flags;
58805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->commandPoolMap[*pCommandPool].queueFamilyIndex = pCreateInfo->queueFamilyIndex;
58815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
58825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
58835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
58845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
588589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo *pCreateInfo,
588689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                               const VkAllocationCallbacks *pAllocator, VkQueryPool *pQueryPool) {
588756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
58880c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    bool skip = false;
58890c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    if (pCreateInfo && pCreateInfo->queryType == VK_QUERY_TYPE_PIPELINE_STATISTICS) {
58900c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis        if (!dev_data->enabled_features.pipelineStatisticsQuery) {
58910c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0,
58920c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis                            __LINE__, VALIDATION_ERROR_01006, "DS",
58930c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis                            "Query pool with type VK_QUERY_TYPE_PIPELINE_STATISTICS created on a device "
58940c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis                            "with VkDeviceCreateInfo.pEnabledFeatures.pipelineStatisticsQuery == VK_FALSE. %s",
58950c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis                            validation_error_map[VALIDATION_ERROR_01006]);
58960c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis        }
58970c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    }
58980c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis
58990c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
59000c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    if (!skip) {
59010c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis        result = dev_data->dispatch_table.CreateQueryPool(device, pCreateInfo, pAllocator, pQueryPool);
59020c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    }
59035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
5904b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
5905eafbf0b68ee6ea6e0bf33f07e0058d00a96efd9aTobin Ehlis        QUERY_POOL_NODE *qp_node = &dev_data->queryPoolMap[*pQueryPool];
5906eafbf0b68ee6ea6e0bf33f07e0058d00a96efd9aTobin Ehlis        qp_node->createInfo = *pCreateInfo;
59075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
59085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
59095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
59105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
59115f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlisstatic bool PreCallValidateDestroyCommandPool(layer_data *dev_data, VkCommandPool pool, COMMAND_POOL_NODE **cp_state) {
59129a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *cp_state = GetCommandPoolNode(dev_data, pool);
5913cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_command_pool) return false;
59145f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    bool skip = false;
59155f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    if (*cp_state) {
59165f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        // Verify that command buffers in pool are complete (not in-flight)
59175f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        skip |= checkCommandBuffersInFlight(dev_data, *cp_state, "destroy command pool with", VALIDATION_ERROR_00077);
59185f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    }
59195f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    return skip;
59205f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis}
59215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
59225f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlisstatic void PostCallRecordDestroyCommandPool(layer_data *dev_data, VkCommandPool pool, COMMAND_POOL_NODE *cp_state) {
59239f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis    // Must remove cmdpool from cmdpoolmap, after removing all cmdbuffers in its list from the commandBufferMap
59245f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    clearCommandBuffersInFlight(dev_data, cp_state);
59255f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    for (auto cb : cp_state->commandBuffers) {
5926a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes        clear_cmd_buf_and_mem_references(dev_data, cb);
59279a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto cb_node = GetCBNode(dev_data, cb);
5928d61de0e68063faa169a9a632f811c9c9adec9897Tobin Ehlis        // Remove references to this cb_node prior to delete
5929d61de0e68063faa169a9a632f811c9c9adec9897Tobin Ehlis        // TODO : Need better solution here, resetCB?
59307165385f3a39f1f951f3a6a9a06ed2cce4642b6dMark Lobodzinski        for (auto obj : cb_node->object_bindings) {
59317165385f3a39f1f951f3a6a9a06ed2cce4642b6dMark Lobodzinski            removeCommandBufferBinding(dev_data, &obj, cb_node);
59327165385f3a39f1f951f3a6a9a06ed2cce4642b6dMark Lobodzinski        }
5933d61de0e68063faa169a9a632f811c9c9adec9897Tobin Ehlis        for (auto framebuffer : cb_node->framebuffers) {
59349a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto fb_state = GetFramebufferState(dev_data, framebuffer);
5935cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (fb_state) fb_state->cb_bindings.erase(cb_node);
5936d61de0e68063faa169a9a632f811c9c9adec9897Tobin Ehlis        }
5937cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        dev_data->commandBufferMap.erase(cb);  // Remove this command buffer
5938cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        delete cb_node;                        // delete CB info structure
5939a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes    }
59405f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    dev_data->commandPoolMap.erase(pool);
59415f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis}
5942e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis
59435f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis// Destroy commandPool along with all of the commandBuffers allocated from that pool
59445f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin EhlisVKAPI_ATTR void VKAPI_CALL DestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks *pAllocator) {
594556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
59465f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    COMMAND_POOL_NODE *cp_state = nullptr;
59475f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
59485f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    bool skip = PreCallValidateDestroyCommandPool(dev_data, commandPool, &cp_state);
59495f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    if (!skip) {
59505f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        lock.unlock();
59515f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        dev_data->dispatch_table.DestroyCommandPool(device, commandPool, pAllocator);
59525f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        lock.lock();
5953405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (commandPool != VK_NULL_HANDLE) {
5954405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyCommandPool(dev_data, commandPool, cp_state);
5955405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
59565f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    }
59575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
59585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5959bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL ResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags) {
596056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
596183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
5962400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis
59631ec6311a8537f4467db08eacbd762ebaa87e70b0Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
59649a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pPool = GetCommandPoolNode(dev_data, commandPool);
5965cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis    skip_call |= checkCommandBuffersInFlight(dev_data, pPool, "reset command pool with", VALIDATION_ERROR_00072);
59661ec6311a8537f4467db08eacbd762ebaa87e70b0Chris Forbes    lock.unlock();
5967a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes
5968cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
59695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
59704a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.ResetCommandPool(device, commandPool, flags);
59715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
59725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Reset all of the CBs allocated from this pool
59735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
59741ec6311a8537f4467db08eacbd762ebaa87e70b0Chris Forbes        lock.lock();
5975a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes        clearCommandBuffersInFlight(dev_data, pPool);
5976a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes        for (auto cmdBuffer : pPool->commandBuffers) {
5977a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes            resetCB(dev_data, cmdBuffer);
59785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
59791ec6311a8537f4467db08eacbd762ebaa87e70b0Chris Forbes        lock.unlock();
59805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
59815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
59825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
59835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
598489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL ResetFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences) {
598556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
598683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
5987b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
59885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < fenceCount; ++i) {
59899a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto pFence = GetFenceNode(dev_data, pFences[i]);
5990090da73358f71ba026e2474a822fecf55267d166Chris Forbes        if (pFence && pFence->state == FENCE_INFLIGHT) {
599183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
59924527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 reinterpret_cast<const uint64_t &>(pFences[i]), __LINE__, VALIDATION_ERROR_00183, "DS",
59934527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 "Fence 0x%" PRIx64 " is in use. %s", reinterpret_cast<const uint64_t &>(pFences[i]),
59944527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 validation_error_map[VALIDATION_ERROR_00183]);
59955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
59965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5997b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
5998090da73358f71ba026e2474a822fecf55267d166Chris Forbes
5999cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
6000090da73358f71ba026e2474a822fecf55267d166Chris Forbes
60014a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.ResetFences(device, fenceCount, pFences);
6002090da73358f71ba026e2474a822fecf55267d166Chris Forbes
6003090da73358f71ba026e2474a822fecf55267d166Chris Forbes    if (result == VK_SUCCESS) {
6004090da73358f71ba026e2474a822fecf55267d166Chris Forbes        lock.lock();
6005090da73358f71ba026e2474a822fecf55267d166Chris Forbes        for (uint32_t i = 0; i < fenceCount; ++i) {
60069a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pFence = GetFenceNode(dev_data, pFences[i]);
6007090da73358f71ba026e2474a822fecf55267d166Chris Forbes            if (pFence) {
6008090da73358f71ba026e2474a822fecf55267d166Chris Forbes                pFence->state = FENCE_UNSIGNALED;
6009090da73358f71ba026e2474a822fecf55267d166Chris Forbes            }
6010090da73358f71ba026e2474a822fecf55267d166Chris Forbes        }
6011090da73358f71ba026e2474a822fecf55267d166Chris Forbes        lock.unlock();
6012090da73358f71ba026e2474a822fecf55267d166Chris Forbes    }
6013090da73358f71ba026e2474a822fecf55267d166Chris Forbes
60145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
60155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
60165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6017e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis// For given cb_nodes, invalidate them and track object causing invalidation
60180a4087f99558069e9f6a437ff2dbb5a9c1c22ccaTobin Ehlisvoid invalidateCommandBuffers(const layer_data *dev_data, std::unordered_set<GLOBAL_CB_NODE *> const &cb_nodes, VK_OBJECT obj) {
6019e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis    for (auto cb_node : cb_nodes) {
602039c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis        if (cb_node->state == CB_RECORDING) {
602139c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis            log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6022fefa20333f94ea75877cca53d0631542cd9d0432Tobin Ehlis                    (uint64_t)(cb_node->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
6023226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    "Invalidating a command buffer that's currently being recorded: 0x%p.", cb_node->commandBuffer);
602439c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis        }
6025e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis        cb_node->state = CB_INVALID;
6026e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis        cb_node->broken_bindings.push_back(obj);
6027e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis    }
6028e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis}
6029e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis
6030c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlisstatic bool PreCallValidateDestroyFramebuffer(layer_data *dev_data, VkFramebuffer framebuffer,
6031c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis                                              FRAMEBUFFER_STATE **framebuffer_state, VK_OBJECT *obj_struct) {
60329a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *framebuffer_state = GetFramebufferState(dev_data, framebuffer);
603394165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(framebuffer), VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT};
6034cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_framebuffer) return false;
6035728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    bool skip = false;
6036728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    if (*framebuffer_state) {
6037728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *framebuffer_state, *obj_struct, VALIDATION_ERROR_00422);
6038728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    }
6039728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    return skip;
6040728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis}
6041728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis
6042c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlisstatic void PostCallRecordDestroyFramebuffer(layer_data *dev_data, VkFramebuffer framebuffer, FRAMEBUFFER_STATE *framebuffer_state,
6043728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis                                             VK_OBJECT obj_struct) {
604439c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, framebuffer_state->cb_bindings, obj_struct);
6045728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    dev_data->frameBufferMap.erase(framebuffer);
6046728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis}
6047728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis
6048bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyFramebuffer(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks *pAllocator) {
604956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
6050c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    FRAMEBUFFER_STATE *framebuffer_state = nullptr;
6051728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    VK_OBJECT obj_struct;
6052b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
6053728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    bool skip = PreCallValidateDestroyFramebuffer(dev_data, framebuffer, &framebuffer_state, &obj_struct);
6054728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    if (!skip) {
6055728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis        lock.unlock();
6056728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis        dev_data->dispatch_table.DestroyFramebuffer(device, framebuffer, pAllocator);
6057728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis        lock.lock();
6058405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (framebuffer != VK_NULL_HANDLE) {
6059405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyFramebuffer(dev_data, framebuffer, framebuffer_state, obj_struct);
6060405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
60615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
60625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
60635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
60640ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlisstatic bool PreCallValidateDestroyRenderPass(layer_data *dev_data, VkRenderPass render_pass, RENDER_PASS_STATE **rp_state,
60650ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis                                             VK_OBJECT *obj_struct) {
60669a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *rp_state = GetRenderPassState(dev_data, render_pass);
606794165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *obj_struct = {reinterpret_cast<uint64_t &>(render_pass), VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT};
6068cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_renderpass) return false;
60690ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    bool skip = false;
60700ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    if (*rp_state) {
60710ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *rp_state, *obj_struct, VALIDATION_ERROR_00393);
60720ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    }
60730ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    return skip;
60740ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis}
60750ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis
60760ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlisstatic void PostCallRecordDestroyRenderPass(layer_data *dev_data, VkRenderPass render_pass, RENDER_PASS_STATE *rp_state,
60770ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis                                            VK_OBJECT obj_struct) {
607839c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, rp_state->cb_bindings, obj_struct);
60790ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    dev_data->renderPassMap.erase(render_pass);
60800ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis}
60810ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis
6082bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks *pAllocator) {
608356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
60840ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    RENDER_PASS_STATE *rp_state = nullptr;
60850ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    VK_OBJECT obj_struct;
6086e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
60870ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    bool skip = PreCallValidateDestroyRenderPass(dev_data, renderPass, &rp_state, &obj_struct);
6088a9fbfe0c622e9fa4b56ddd015ed4c3c409020c2eTobin Ehlis    if (!skip) {
6089a9fbfe0c622e9fa4b56ddd015ed4c3c409020c2eTobin Ehlis        lock.unlock();
60904a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyRenderPass(device, renderPass, pAllocator);
60910ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis        lock.lock();
6092405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (renderPass != VK_NULL_HANDLE) {
6093405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyRenderPass(dev_data, renderPass, rp_state, obj_struct);
6094405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
6095a9fbfe0c622e9fa4b56ddd015ed4c3c409020c2eTobin Ehlis    }
60965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
60975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
609889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo,
609989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                            const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer) {
610056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
61013683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    std::unique_lock<std::mutex> lock(global_lock);
61023683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    bool skip = PreCallValidateCreateBuffer(dev_data, pCreateInfo);
61033683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    lock.unlock();
61043683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski
61053683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
61064a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateBuffer(device, pCreateInfo, pAllocator, pBuffer);
61075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
61085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
61093683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski        lock.lock();
61103683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski        PostCallRecordCreateBuffer(dev_data, pCreateInfo, pBuffer);
61113683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski        lock.unlock();
61125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
61135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
61145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
61155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
611689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateBufferView(VkDevice device, const VkBufferViewCreateInfo *pCreateInfo,
611789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                const VkAllocationCallbacks *pAllocator, VkBufferView *pView) {
611856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
61198c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    std::unique_lock<std::mutex> lock(global_lock);
61208c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    bool skip_call = PreCallValidateCreateBufferView(dev_data, pCreateInfo);
61218c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    lock.unlock();
6122cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
61234a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateBufferView(device, pCreateInfo, pAllocator, pView);
61245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
61258c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young        lock.lock();
61263683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski        PostCallRecordCreateBufferView(dev_data, pCreateInfo, pView);
61278c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young        lock.unlock();
61285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
61295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
61305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
61315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
61328dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski// Access helper functions for external modules
6133d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinskiconst VkFormatProperties *GetFormatProperties(core_validation::layer_data *device_data, VkFormat format) {
6134d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    VkFormatProperties *format_properties = new VkFormatProperties;
6135d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    instance_layer_data *instance_data =
6136d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski        GetLayerDataPtr(get_dispatch_key(device_data->instance_data->instance), instance_layer_data_map);
6137d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    instance_data->dispatch_table.GetPhysicalDeviceFormatProperties(device_data->physical_device, format, format_properties);
6138d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    return format_properties;
61398dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski}
61408dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski
6141d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinskiconst VkImageFormatProperties *GetImageFormatProperties(core_validation::layer_data *device_data, VkFormat format,
6142d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski                                                        VkImageType image_type, VkImageTiling tiling, VkImageUsageFlags usage,
6143d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski                                                        VkImageCreateFlags flags) {
6144d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    VkImageFormatProperties *image_format_properties = new VkImageFormatProperties;
6145d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    instance_layer_data *instance_data =
6146d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski        GetLayerDataPtr(get_dispatch_key(device_data->instance_data->instance), instance_layer_data_map);
6147d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    instance_data->dispatch_table.GetPhysicalDeviceImageFormatProperties(device_data->physical_device, format, image_type, tiling,
6148d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski                                                                         usage, flags, image_format_properties);
6149d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    return image_format_properties;
61508dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski}
61518dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski
61527a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlisconst debug_report_data *GetReportData(const core_validation::layer_data *device_data) { return device_data->report_data; }
61538dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski
61548dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinskiconst VkPhysicalDeviceProperties *GetPhysicalDeviceProperties(core_validation::layer_data *device_data) {
61558dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski    return &device_data->phys_dev_props;
61568dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski}
61578dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski
61588c59133586421be878d393799b30044497f77727Mark Lobodzinskiconst CHECK_DISABLED *GetDisables(core_validation::layer_data *device_data) { return &device_data->instance_data->disabled; }
61598c59133586421be878d393799b30044497f77727Mark Lobodzinski
61608c59133586421be878d393799b30044497f77727Mark Lobodzinskistd::unordered_map<VkImage, std::unique_ptr<IMAGE_STATE>> *GetImageMap(core_validation::layer_data *device_data) {
61618c59133586421be878d393799b30044497f77727Mark Lobodzinski    return &device_data->imageMap;
61628c59133586421be878d393799b30044497f77727Mark Lobodzinski}
61638c59133586421be878d393799b30044497f77727Mark Lobodzinski
61648c59133586421be878d393799b30044497f77727Mark Lobodzinskistd::unordered_map<VkImage, std::vector<ImageSubresourcePair>> *GetImageSubresourceMap(core_validation::layer_data *device_data) {
61658c59133586421be878d393799b30044497f77727Mark Lobodzinski    return &device_data->imageSubresourceMap;
61668c59133586421be878d393799b30044497f77727Mark Lobodzinski}
61678c59133586421be878d393799b30044497f77727Mark Lobodzinski
61688c59133586421be878d393799b30044497f77727Mark Lobodzinskistd::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> *GetImageLayoutMap(layer_data *device_data) {
61698c59133586421be878d393799b30044497f77727Mark Lobodzinski    return &device_data->imageLayoutMap;
61708c59133586421be878d393799b30044497f77727Mark Lobodzinski}
61718c59133586421be878d393799b30044497f77727Mark Lobodzinski
61723683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinskistd::unordered_map<VkBuffer, std::unique_ptr<BUFFER_STATE>> *GetBufferMap(layer_data *device_data) {
61733683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    return &device_data->bufferMap;
61743683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski}
61753683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski
61763683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinskistd::unordered_map<VkBufferView, std::unique_ptr<BUFFER_VIEW_STATE>> *GetBufferViewMap(layer_data *device_data) {
61773683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    return &device_data->bufferViewMap;
61783683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski}
61793683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski
61801c143ebdb651ea034e0b1f8731cb9f361e2f8b82Mark Lobodzinskistd::unordered_map<VkImageView, std::unique_ptr<IMAGE_VIEW_STATE>> *GetImageViewMap(layer_data *device_data) {
61811c143ebdb651ea034e0b1f8731cb9f361e2f8b82Mark Lobodzinski    return &device_data->imageViewMap;
61821c143ebdb651ea034e0b1f8731cb9f361e2f8b82Mark Lobodzinski}
61831c143ebdb651ea034e0b1f8731cb9f361e2f8b82Mark Lobodzinski
6184d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinskiconst PHYS_DEV_PROPERTIES_NODE *GetPhysDevProperties(const layer_data *device_data) {
61856a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    return &device_data->phys_dev_properties;
61866a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski}
61876a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski
61885f3e7c34de87353f38bbcd79e12de8af4a9e7695Mark Lobodzinskiconst VkPhysicalDeviceFeatures *GetEnabledFeatures(const layer_data *device_data) {
61895f3e7c34de87353f38bbcd79e12de8af4a9e7695Mark Lobodzinski    return &device_data->enabled_features;
61905f3e7c34de87353f38bbcd79e12de8af4a9e7695Mark Lobodzinski}
61915f3e7c34de87353f38bbcd79e12de8af4a9e7695Mark Lobodzinski
61920e2296e24065d02615ee87561bbb80af414a1ddfMike Schuchardtconst devExts *GetDeviceExtensions(const layer_data *device_data) { return &device_data->device_extensions; }
61930e2296e24065d02615ee87561bbb80af414a1ddfMike Schuchardt
619489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo,
619589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                           const VkAllocationCallbacks *pAllocator, VkImage *pImage) {
61968dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
619756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
61988dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski    bool skip = PreCallValidateCreateImage(dev_data, pCreateInfo, pAllocator, pImage);
61998dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski    if (!skip) {
62008dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski        result = dev_data->dispatch_table.CreateImage(device, pCreateInfo, pAllocator, pImage);
62018dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski    }
62025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6203b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
6204920311b6aa5614a545cad59521770d0898a75d65Mark Lobodzinski        PostCallRecordCreateImage(dev_data, pCreateInfo, pImage);
62055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
62065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
62075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
62085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
62098c07a094dc9cc4afb6b62181f341c12b9e969041Mark YoungVKAPI_ATTR VkResult VKAPI_CALL CreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo,
62108c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young                                               const VkAllocationCallbacks *pAllocator, VkImageView *pView) {
621156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
62128c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    std::unique_lock<std::mutex> lock(global_lock);
6213e3effabf8e97cae8e006477806ceaca62e4f2ce7Tobin Ehlis    bool skip = PreCallValidateCreateImageView(dev_data, pCreateInfo);
62148c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    lock.unlock();
6215cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
62164a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateImageView(device, pCreateInfo, pAllocator, pView);
62175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
62188c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young        lock.lock();
621979fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis        PostCallRecordCreateImageView(dev_data, pCreateInfo, *pView);
62208c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young        lock.unlock();
62215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6222bb6624cb996175d8945190886a200e720b3871efChris Forbes
62235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
62245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
62255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6226bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateFence(VkDevice device, const VkFenceCreateInfo *pCreateInfo,
6227bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           const VkAllocationCallbacks *pAllocator, VkFence *pFence) {
622856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
62294a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateFence(device, pCreateInfo, pAllocator, pFence);
62305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6231b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
6232a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        auto &fence_node = dev_data->fenceMap[*pFence];
62338988ad37ea5a054ff2ae3cbe4b767ae6c13cf48bChris Forbes        fence_node.fence = *pFence;
6234a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        fence_node.createInfo = *pCreateInfo;
6235cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes        fence_node.state = (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) ? FENCE_RETIRED : FENCE_UNSIGNALED;
62365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
62375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
62385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
62395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
62405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// TODO handle pipeline caches
624189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreatePipelineCache(VkDevice device, const VkPipelineCacheCreateInfo *pCreateInfo,
624289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                   const VkAllocationCallbacks *pAllocator, VkPipelineCache *pPipelineCache) {
624356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
62444a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreatePipelineCache(device, pCreateInfo, pAllocator, pPipelineCache);
62455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
62465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
62475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6248bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyPipelineCache(VkDevice device, VkPipelineCache pipelineCache,
6249bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkAllocationCallbacks *pAllocator) {
625056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
62514a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.DestroyPipelineCache(device, pipelineCache, pAllocator);
62525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
62535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6254bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL GetPipelineCacheData(VkDevice device, VkPipelineCache pipelineCache, size_t *pDataSize,
6255bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                    void *pData) {
625656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
62574a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.GetPipelineCacheData(device, pipelineCache, pDataSize, pData);
62585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
62595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
62605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6261bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL MergePipelineCaches(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount,
6262bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   const VkPipelineCache *pSrcCaches) {
626356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
62644a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.MergePipelineCaches(device, dstCache, srcCacheCount, pSrcCaches);
62655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
62665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
62675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
62683d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis// utility function to set collective state for pipeline
62694c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisvoid set_pipeline_state(PIPELINE_STATE *pPipe) {
62703d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    // If any attachment used by this pipeline has blendEnable, set top-level blendEnable
62713d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    if (pPipe->graphicsPipelineCI.pColorBlendState) {
62723d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        for (size_t i = 0; i < pPipe->attachments.size(); ++i) {
62733d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis            if (VK_TRUE == pPipe->attachments[i].blendEnable) {
62743d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                if (((pPipe->attachments[i].dstAlphaBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
62753d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                     (pPipe->attachments[i].dstAlphaBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
62763d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                    ((pPipe->attachments[i].dstColorBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
62773d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                     (pPipe->attachments[i].dstColorBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
62783d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                    ((pPipe->attachments[i].srcAlphaBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
62793d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                     (pPipe->attachments[i].srcAlphaBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
62803d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                    ((pPipe->attachments[i].srcColorBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
62813d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                     (pPipe->attachments[i].srcColorBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA))) {
62823d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                    pPipe->blendConstantsEnabled = true;
62833d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                }
62843d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis            }
62853d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        }
62863d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
62873d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis}
62883d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis
6289daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinskibool validate_dual_src_blend_feature(layer_data *device_data, PIPELINE_STATE *pipe_state) {
6290daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski    bool skip = false;
6291daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski    if (pipe_state->graphicsPipelineCI.pColorBlendState) {
6292daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski        for (size_t i = 0; i < pipe_state->attachments.size(); ++i) {
6293daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski            if (!device_data->enabled_features.dualSrcBlend) {
6294daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                if ((pipe_state->attachments[i].dstAlphaBlendFactor == VK_BLEND_FACTOR_SRC1_COLOR) ||
6295daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    (pipe_state->attachments[i].dstAlphaBlendFactor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR) ||
6296daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    (pipe_state->attachments[i].dstAlphaBlendFactor == VK_BLEND_FACTOR_SRC1_ALPHA) ||
6297daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    (pipe_state->attachments[i].dstAlphaBlendFactor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA) ||
6298daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    (pipe_state->attachments[i].srcAlphaBlendFactor == VK_BLEND_FACTOR_SRC1_COLOR) ||
6299daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    (pipe_state->attachments[i].srcAlphaBlendFactor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR) ||
6300daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    (pipe_state->attachments[i].srcAlphaBlendFactor == VK_BLEND_FACTOR_SRC1_ALPHA) ||
6301daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    (pipe_state->attachments[i].srcAlphaBlendFactor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA)) {
6302daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    skip |=
6303daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                        log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
6304daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                                reinterpret_cast<uint64_t &>(pipe_state->pipeline), __LINE__, DRAWSTATE_INVALID_FEATURE, "DS",
6305daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                                "CmdBindPipeline: vkPipeline (0x%" PRIxLEAST64 ") attachment[" PRINTF_SIZE_T_SPECIFIER
6306daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                                "] has a dual-source blend factor but this device feature is not enabled.",
6307daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                                reinterpret_cast<uint64_t &>(pipe_state->pipeline), i);
6308daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                }
6309daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski            }
6310daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski        }
6311daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski    }
6312daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski    return skip;
6313daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski}
6314daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski
631548b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinskistatic bool PreCallCreateGraphicsPipelines(layer_data *device_data, uint32_t count,
631648b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski                                           const VkGraphicsPipelineCreateInfo *create_infos, vector<PIPELINE_STATE *> &pipe_state) {
631748b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski    bool skip = false;
6318bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    instance_layer_data *instance_data =
631956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        GetLayerDataPtr(get_dispatch_key(device_data->instance_data->instance), instance_layer_data_map);
632048b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski
632148b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski    for (uint32_t i = 0; i < count; i++) {
632248b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski        skip |= verifyPipelineCreateState(device_data, pipe_state, i);
632378b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski        if (create_infos[i].pVertexInputState != NULL) {
632478b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski            for (uint32_t j = 0; j < create_infos[i].pVertexInputState->vertexAttributeDescriptionCount; j++) {
632578b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                VkFormat format = create_infos[i].pVertexInputState->pVertexAttributeDescriptions[j].format;
632678b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                // Internal call to get format info.  Still goes through layers, could potentially go directly to ICD.
632778b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                VkFormatProperties properties;
632878b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                instance_data->dispatch_table.GetPhysicalDeviceFormatProperties(device_data->physical_device, format, &properties);
632978b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                if ((properties.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT) == 0) {
633078b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                    skip |= log_msg(
633178b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                        device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
633278b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                        __LINE__, VALIDATION_ERROR_01413, "IMAGE",
633378b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                        "vkCreateGraphicsPipelines: pCreateInfo[%d].pVertexInputState->vertexAttributeDescriptions[%d].format "
633478b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                        "(%s) is not a supported vertex buffer format. %s",
633578b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                        i, j, string_VkFormat(format), validation_error_map[VALIDATION_ERROR_01413]);
633678b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                }
633778b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski            }
633878b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski        }
633948b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski    }
634048b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski    return skip;
634148b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski}
634248b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski
6343bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
6344bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                       const VkGraphicsPipelineCreateInfo *pCreateInfos,
6345bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                       const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) {
63465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO What to do with pipelineCache?
63475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // The order of operations here is a little convoluted but gets the job done
63484c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    //  1. Pipeline create state is first shadowed into PIPELINE_STATE struct
63495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    //  2. Create state is then validated (which uses flags setup during shadowing)
63505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    //  3. If everything looks good, we'll then create the pipeline and add NODE to pipelineMap
635142486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski    bool skip = false;
63525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO : Improve this data struct w/ unique_ptrs so cleanup below is automatic
635342486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski    vector<PIPELINE_STATE *> pipe_state(count);
635456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
63555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
63565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t i = 0;
6357b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
63585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
63595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (i = 0; i < count; i++) {
636042486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski        pipe_state[i] = new PIPELINE_STATE;
636142486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski        pipe_state[i]->initGraphicsPipeline(&pCreateInfos[i]);
63629a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        pipe_state[i]->render_pass_ci.initialize(GetRenderPassState(dev_data, pCreateInfos[i].renderPass)->createInfo.ptr());
636342486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski        pipe_state[i]->pipeline_layout = *getPipelineLayout(dev_data, pCreateInfos[i].layout);
63645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
636542486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski    skip |= PreCallCreateGraphicsPipelines(dev_data, count, pCreateInfos, pipe_state);
63665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6367c70226063be6148056ceeccf835175a1fd59f24fChris Forbes    if (skip) {
6368c70226063be6148056ceeccf835175a1fd59f24fChris Forbes        for (i = 0; i < count; i++) {
6369c70226063be6148056ceeccf835175a1fd59f24fChris Forbes            delete pipe_state[i];
63701ab616b32d4e5b7d62d4a8c41b0c03ea335ab845Chris Forbes            pPipelines[i] = VK_NULL_HANDLE;
6371c70226063be6148056ceeccf835175a1fd59f24fChris Forbes        }
63727a456d188475c23b566334be45dc0489b2789653Chris Forbes        return VK_ERROR_VALIDATION_FAILED_EXT;
63737a456d188475c23b566334be45dc0489b2789653Chris Forbes    }
63747a456d188475c23b566334be45dc0489b2789653Chris Forbes
63757a456d188475c23b566334be45dc0489b2789653Chris Forbes    lock.unlock();
6376bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result =
6377bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        dev_data->dispatch_table.CreateGraphicsPipelines(device, pipelineCache, count, pCreateInfos, pAllocator, pPipelines);
63787a456d188475c23b566334be45dc0489b2789653Chris Forbes    lock.lock();
63797a456d188475c23b566334be45dc0489b2789653Chris Forbes    for (i = 0; i < count; i++) {
638061943a7503bc8594338f3364ef42f1d863486c04Chris Forbes        if (pPipelines[i] == VK_NULL_HANDLE) {
638161943a7503bc8594338f3364ef42f1d863486c04Chris Forbes            delete pipe_state[i];
6382bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        } else {
638361943a7503bc8594338f3364ef42f1d863486c04Chris Forbes            pipe_state[i]->pipeline = pPipelines[i];
638461943a7503bc8594338f3364ef42f1d863486c04Chris Forbes            dev_data->pipelineMap[pipe_state[i]->pipeline] = pipe_state[i];
638561943a7503bc8594338f3364ef42f1d863486c04Chris Forbes        }
63865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6387c70226063be6148056ceeccf835175a1fd59f24fChris Forbes
63885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
63895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
63905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6391bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
6392bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      const VkComputePipelineCreateInfo *pCreateInfos,
6393bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) {
63940108a1af0b7c6949846e9d71d00bbfb322b6f7caChris Forbes    bool skip = false;
63955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
63965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO : Improve this data struct w/ unique_ptrs so cleanup below is automatic
63974c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    vector<PIPELINE_STATE *> pPipeState(count);
639856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
63995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
64005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t i = 0;
6401b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
64025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (i = 0; i < count; i++) {
64035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // TODO: Verify compute stage bits
64045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
64055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Create and initialize internal tracking data structure
64064c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis        pPipeState[i] = new PIPELINE_STATE;
64074c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis        pPipeState[i]->initComputePipeline(&pCreateInfos[i]);
6408c2a5a36d03bbe52f5854a5884346e4a84115e259Tobin Ehlis        pPipeState[i]->pipeline_layout = *getPipelineLayout(dev_data, pCreateInfos[i].layout);
64095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
64105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // TODO: Add Compute Pipeline Verification
6411ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes        skip |= !validate_compute_pipeline(dev_data, pPipeState[i]);
64120108a1af0b7c6949846e9d71d00bbfb322b6f7caChris Forbes        // skip |= verifyPipelineCreateState(dev_data, pPipeState[i]);
64135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
64145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
64157a456d188475c23b566334be45dc0489b2789653Chris Forbes    if (skip) {
64165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (i = 0; i < count; i++) {
64175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Clean up any locally allocated data structures
64184c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis            delete pPipeState[i];
6419fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes            pPipelines[i] = VK_NULL_HANDLE;
64205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
64215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return VK_ERROR_VALIDATION_FAILED_EXT;
64225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
64237a456d188475c23b566334be45dc0489b2789653Chris Forbes
64247a456d188475c23b566334be45dc0489b2789653Chris Forbes    lock.unlock();
6425bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result =
6426bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        dev_data->dispatch_table.CreateComputePipelines(device, pipelineCache, count, pCreateInfos, pAllocator, pPipelines);
64277a456d188475c23b566334be45dc0489b2789653Chris Forbes    lock.lock();
64287a456d188475c23b566334be45dc0489b2789653Chris Forbes    for (i = 0; i < count; i++) {
6429fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes        if (pPipelines[i] == VK_NULL_HANDLE) {
6430fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes            delete pPipeState[i];
6431bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        } else {
6432fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes            pPipeState[i]->pipeline = pPipelines[i];
6433fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes            dev_data->pipelineMap[pPipeState[i]->pipeline] = pPipeState[i];
6434fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes        }
64357a456d188475c23b566334be45dc0489b2789653Chris Forbes    }
64367a456d188475c23b566334be45dc0489b2789653Chris Forbes
64375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
64385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
64395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
644089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateSampler(VkDevice device, const VkSamplerCreateInfo *pCreateInfo,
644189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                             const VkAllocationCallbacks *pAllocator, VkSampler *pSampler) {
644256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
64434a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateSampler(device, pCreateInfo, pAllocator, pSampler);
64445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6445b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
6446d31a44af6da568692a73201825459689c9431867Tobin Ehlis        dev_data->samplerMap[*pSampler] = unique_ptr<SAMPLER_STATE>(new SAMPLER_STATE(pSampler, pCreateInfo));
64475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
64485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
64495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
64505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
64510c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlisstatic bool PreCallValidateCreateDescriptorSetLayout(layer_data *dev_data, const VkDescriptorSetLayoutCreateInfo *create_info) {
6452cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.create_descriptor_set_layout) return false;
64530c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    return cvdescriptorset::DescriptorSetLayout::ValidateCreateInfo(dev_data->report_data, create_info);
64540c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis}
64550c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis
64560c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlisstatic void PostCallRecordCreateDescriptorSetLayout(layer_data *dev_data, const VkDescriptorSetLayoutCreateInfo *create_info,
64570c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis                                                    VkDescriptorSetLayout set_layout) {
64583f1d2ba6852cf6b1bb4e1f06d690293565108e2cTobin Ehlis    // TODO: Convert this to unique_ptr to avoid leaks
64590c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    dev_data->descriptorSetLayoutMap[set_layout] = new cvdescriptorset::DescriptorSetLayout(create_info, set_layout);
64600c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis}
64610c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis
6462bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
6463bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                         const VkAllocationCallbacks *pAllocator,
6464bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                         VkDescriptorSetLayout *pSetLayout) {
646556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
64660c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
64670c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
64680c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    bool skip = PreCallValidateCreateDescriptorSetLayout(dev_data, pCreateInfo);
64690c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    if (!skip) {
64700c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis        lock.unlock();
64710c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis        result = dev_data->dispatch_table.CreateDescriptorSetLayout(device, pCreateInfo, pAllocator, pSetLayout);
64720c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis        if (VK_SUCCESS == result) {
64730c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis            lock.lock();
64740c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis            PostCallRecordCreateDescriptorSetLayout(dev_data, pCreateInfo, *pSetLayout);
64750c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis        }
64765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
64775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
64785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
64795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
64809e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz// Used by CreatePipelineLayout and CmdPushConstants.
64819e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz// Note that the index argument is optional and only used by CreatePipelineLayout.
64829e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultzstatic bool validatePushConstantRange(const layer_data *dev_data, const uint32_t offset, const uint32_t size,
64839e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz                                      const char *caller_name, uint32_t index = 0) {
6484cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.push_constant_range) return false;
64859e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    uint32_t const maxPushConstantsSize = dev_data->phys_dev_properties.properties.limits.maxPushConstantsSize;
648683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
64879e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // Check that offset + size don't exceed the max.
64889e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // Prevent arithetic overflow here by avoiding addition and testing in this order.
64899e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    if ((offset >= maxPushConstantsSize) || (size > maxPushConstantsSize - offset)) {
64909e24d8153ab63bc3ac08b5a1517c203930b5de91Karl 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.
64919e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        if (0 == strcmp(caller_name, "vkCreatePipelineLayout()")) {
6492e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis            if (offset >= maxPushConstantsSize) {
6493e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis                skip_call |=
6494df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6495df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            __LINE__, VALIDATION_ERROR_00877, "DS",
6496cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s call has push constants index %u with offset %u that "
6497cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "exceeds this device's maxPushConstantSize of %u. %s",
6498e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis                            caller_name, index, offset, maxPushConstantsSize, validation_error_map[VALIDATION_ERROR_00877]);
6499e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis            }
6500e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis            if (size > maxPushConstantsSize - offset) {
6501e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis                skip_call |=
6502df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6503df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            __LINE__, VALIDATION_ERROR_00880, "DS",
6504cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s call has push constants index %u with offset %u and size %u that "
6505cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "exceeds this device's maxPushConstantSize of %u. %s",
6506e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis                            caller_name, index, offset, size, maxPushConstantsSize, validation_error_map[VALIDATION_ERROR_00880]);
6507e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis            }
65089e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else if (0 == strcmp(caller_name, "vkCmdPushConstants()")) {
65094527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            if (offset >= maxPushConstantsSize) {
65104527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                skip_call |=
6511df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6512df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            __LINE__, VALIDATION_ERROR_00991, "DS",
6513cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s call has push constants index %u with offset %u that "
6514cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "exceeds this device's maxPushConstantSize of %u. %s",
65154527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            caller_name, index, offset, maxPushConstantsSize, validation_error_map[VALIDATION_ERROR_00991]);
65164527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            }
65174527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            if (size > maxPushConstantsSize - offset) {
65184527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                skip_call |=
6519df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6520df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            __LINE__, VALIDATION_ERROR_00992, "DS",
6521cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s call has push constants index %u with offset %u and size %u that "
6522cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "exceeds this device's maxPushConstantSize of %u. %s",
65234527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            caller_name, index, offset, size, maxPushConstantsSize, validation_error_map[VALIDATION_ERROR_00992]);
65244527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            }
65259e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else {
6526df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6527df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                 __LINE__, DRAWSTATE_INTERNAL_ERROR, "DS", "%s caller not supported.", caller_name);
65289e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
65299e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    }
65309e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // size needs to be non-zero and a multiple of 4.
65319e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    if ((size == 0) || ((size & 0x3) != 0)) {
65329e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        if (0 == strcmp(caller_name, "vkCreatePipelineLayout()")) {
6533891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis            if (size == 0) {
6534df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
6535df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                     0, __LINE__, VALIDATION_ERROR_00878, "DS",
6536cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "%s call has push constants index %u with "
6537cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "size %u. Size must be greater than zero. %s",
6538891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis                                     caller_name, index, size, validation_error_map[VALIDATION_ERROR_00878]);
6539891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis            }
6540891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis            if (size & 0x3) {
6541df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
6542df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                     0, __LINE__, VALIDATION_ERROR_00879, "DS",
6543cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "%s call has push constants index %u with "
6544cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "size %u. Size must be a multiple of 4. %s",
6545891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis                                     caller_name, index, size, validation_error_map[VALIDATION_ERROR_00879]);
6546891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis            }
65479e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else if (0 == strcmp(caller_name, "vkCmdPushConstants()")) {
65484527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            if (size == 0) {
6549df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
6550df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                     0, __LINE__, VALIDATION_ERROR_01000, "DS",
6551cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "%s call has push constants index %u with "
6552cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "size %u. Size must be greater than zero. %s",
65534527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                     caller_name, index, size, validation_error_map[VALIDATION_ERROR_01000]);
65544527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            }
65554527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            if (size & 0x3) {
6556df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
6557df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                     0, __LINE__, VALIDATION_ERROR_00990, "DS",
6558cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "%s call has push constants index %u with "
6559cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                     "size %u. Size must be a multiple of 4. %s",
65604527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                     caller_name, index, size, validation_error_map[VALIDATION_ERROR_00990]);
65614527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            }
65629e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else {
6563df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6564df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                 __LINE__, DRAWSTATE_INTERNAL_ERROR, "DS", "%s caller not supported.", caller_name);
65659e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
65669e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    }
65679e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // offset needs to be a multiple of 4.
65689e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    if ((offset & 0x3) != 0) {
65699e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        if (0 == strcmp(caller_name, "vkCreatePipelineLayout()")) {
6570df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6571df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                 __LINE__, VALIDATION_ERROR_02521, "DS",
6572cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "%s call has push constants index %u with "
6573cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "offset %u. Offset must be a multiple of 4. %s",
65744527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 caller_name, index, offset, validation_error_map[VALIDATION_ERROR_02521]);
65759e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else if (0 == strcmp(caller_name, "vkCmdPushConstants()")) {
6576df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6577df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                 __LINE__, VALIDATION_ERROR_00989, "DS",
6578cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "%s call has push constants with "
6579cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "offset %u. Offset must be a multiple of 4. %s",
65804527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 caller_name, offset, validation_error_map[VALIDATION_ERROR_00989]);
65819e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else {
6582df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6583df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                 __LINE__, DRAWSTATE_INTERNAL_ERROR, "DS", "%s caller not supported.", caller_name);
65849e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
65855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
658683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
65875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
65885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6589bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo *pCreateInfo,
659089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                    const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout) {
659183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
659256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
6593bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz    // TODO : Add checks for VALIDATION_ERRORS 865-870
65949e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // Push Constant Range checks
659507a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz    uint32_t i, j;
65965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
659783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis        skip_call |= validatePushConstantRange(dev_data, pCreateInfo->pPushConstantRanges[i].offset,
659883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                               pCreateInfo->pPushConstantRanges[i].size, "vkCreatePipelineLayout()", i);
65999e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        if (0 == pCreateInfo->pPushConstantRanges[i].stageFlags) {
6600df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6601df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                 __LINE__, VALIDATION_ERROR_00882, "DS", "vkCreatePipelineLayout() call has no stageFlags set. %s",
66024527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                 validation_error_map[VALIDATION_ERROR_00882]);
66039e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
66049e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    }
6605cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
660607a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz
6607bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz    // As of 1.0.28, there is a VU that states that a stage flag cannot appear more than once in the list of push constant ranges.
660807a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz    for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
660907a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz        for (j = i + 1; j < pCreateInfo->pushConstantRangeCount; ++j) {
6610bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz            if (0 != (pCreateInfo->pPushConstantRanges[i].stageFlags & pCreateInfo->pPushConstantRanges[j].stageFlags)) {
6611df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
6612df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                     0, __LINE__, VALIDATION_ERROR_00871, "DS",
6613bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz                                     "vkCreatePipelineLayout() Duplicate stage flags found in ranges %d and %d. %s", i, j,
6614bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz                                     validation_error_map[VALIDATION_ERROR_00871]);
66159e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz            }
66165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
66175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6618f73b2046273413ea1338dd714d67c39f8e0fa09eChris Forbes
66194a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreatePipelineLayout(device, pCreateInfo, pAllocator, pPipelineLayout);
66205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6621b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
66225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        PIPELINE_LAYOUT_NODE &plNode = dev_data->pipelineLayoutMap[*pPipelineLayout];
662369b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis        plNode.layout = *pPipelineLayout;
6624416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis        plNode.set_layouts.resize(pCreateInfo->setLayoutCount);
66255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (i = 0; i < pCreateInfo->setLayoutCount; ++i) {
66269a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            plNode.set_layouts[i] = GetDescriptorSetLayout(dev_data, pCreateInfo->pSetLayouts[i]);
66275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6628416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis        plNode.push_constant_ranges.resize(pCreateInfo->pushConstantRangeCount);
66295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
6630416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis            plNode.push_constant_ranges[i] = pCreateInfo->pPushConstantRanges[i];
66315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
66325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
66335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
66345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
66355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6636bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateDescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo *pCreateInfo,
6637bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                    const VkAllocationCallbacks *pAllocator, VkDescriptorPool *pDescriptorPool) {
663856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
66394a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateDescriptorPool(device, pCreateInfo, pAllocator, pDescriptorPool);
66405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
66415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
6642414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                    (uint64_t)*pDescriptorPool, __LINE__, DRAWSTATE_OUT_OF_MEMORY, "DS", "Created Descriptor Pool 0x%" PRIxLEAST64,
66435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    (uint64_t)*pDescriptorPool))
66445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return VK_ERROR_VALIDATION_FAILED_EXT;
6645a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis        DESCRIPTOR_POOL_STATE *pNewNode = new DESCRIPTOR_POOL_STATE(*pDescriptorPool, pCreateInfo);
66465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (NULL == pNewNode) {
66475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
66485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        (uint64_t)*pDescriptorPool, __LINE__, DRAWSTATE_OUT_OF_MEMORY, "DS",
6649a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis                        "Out of memory while attempting to allocate DESCRIPTOR_POOL_STATE in vkCreateDescriptorPool()"))
66505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return VK_ERROR_VALIDATION_FAILED_EXT;
66515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
6652b9e992386a44404152747d66817a733aa127e281Jeremy Hayes            std::lock_guard<std::mutex> lock(global_lock);
66535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->descriptorPoolMap[*pDescriptorPool] = pNewNode;
66545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
66555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
66565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Need to do anything if pool create fails?
66575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
66585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
66595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
66605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6661bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL ResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool,
6662bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   VkDescriptorPoolResetFlags flags) {
66637286e20c06011d3c6fa7edfbdbadd42bb6e8cc35Tobin Ehlis    // TODO : Add checks for VALIDATION_ERROR_00928
666456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
66654a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.ResetDescriptorPool(device, descriptorPool, flags);
66665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6667b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
66685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        clearDescriptorPool(dev_data, device, descriptorPool, flags);
66695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
66705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
66715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
66722c4e180a4442f968b44f3d5136f7ffda706f6428Chris Forbes// Ensure the pool contains enough descriptors and descriptor sets to satisfy
6673789832b514862c7a7b5b847eeb8e7cacb733b77bTobin Ehlis// an allocation request. Fills common_data with the total number of descriptors of each type required,
6674789832b514862c7a7b5b847eeb8e7cacb733b77bTobin Ehlis// as well as DescriptorSetLayout ptrs used for later update.
66757f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlisstatic bool PreCallValidateAllocateDescriptorSets(layer_data *dev_data, const VkDescriptorSetAllocateInfo *pAllocateInfo,
66767f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis                                                  cvdescriptorset::AllocateDescriptorSetsData *common_data) {
66777a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    // Always update common data
66787a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    cvdescriptorset::UpdateAllocateDescriptorSetsData(dev_data, pAllocateInfo, common_data);
6679cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.allocate_descriptor_sets) return false;
66807e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlis    // All state checks for AllocateDescriptorSets is done in single function
66817a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    return cvdescriptorset::ValidateAllocateDescriptorSets(dev_data, pAllocateInfo, common_data);
66827e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlis}
66837e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlis// Allocation state was good and call down chain was made so update state based on allocating descriptor sets
66847e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlisstatic void PostCallRecordAllocateDescriptorSets(layer_data *dev_data, const VkDescriptorSetAllocateInfo *pAllocateInfo,
66857f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis                                                 VkDescriptorSet *pDescriptorSets,
66867f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis                                                 const cvdescriptorset::AllocateDescriptorSetsData *common_data) {
66877e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlis    // All the updates are contained in a single cvdescriptorset function
66882c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    cvdescriptorset::PerformAllocateDescriptorSets(pAllocateInfo, pDescriptorSets, common_data, &dev_data->descriptorPoolMap,
6689b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis                                                   &dev_data->setMap, dev_data);
66902c4e180a4442f968b44f3d5136f7ffda706f6428Chris Forbes}
66912c4e180a4442f968b44f3d5136f7ffda706f6428Chris Forbes
6692bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL AllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo,
6693bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      VkDescriptorSet *pDescriptorSets) {
669456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
6695b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
66967f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis    cvdescriptorset::AllocateDescriptorSetsData common_data(pAllocateInfo->descriptorSetCount);
66977f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis    bool skip_call = PreCallValidateAllocateDescriptorSets(dev_data, pAllocateInfo, &common_data);
6698b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
6699d173e0daab123373ce75105f2a908f6ae7cef6abChris Forbes
6700cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
6701d173e0daab123373ce75105f2a908f6ae7cef6abChris Forbes
67024a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.AllocateDescriptorSets(device, pAllocateInfo, pDescriptorSets);
67036511ce241f7f210211e0c0e882f3c14889071f4dChris Forbes
67045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6705b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
67067f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis        PostCallRecordAllocateDescriptorSets(dev_data, pAllocateInfo, pDescriptorSets, &common_data);
6707b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
67085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
67095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
67105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
6711cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis// Verify state before freeing DescriptorSets
6712cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlisstatic bool PreCallValidateFreeDescriptorSets(const layer_data *dev_data, VkDescriptorPool pool, uint32_t count,
6713cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis                                              const VkDescriptorSet *descriptor_sets) {
6714cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.free_descriptor_sets) return false;
6715cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    bool skip_call = false;
6716cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    // First make sure sets being destroyed are not currently in-use
6717405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour    for (uint32_t i = 0; i < count; ++i) {
6718405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (descriptor_sets[i] != VK_NULL_HANDLE) {
6719405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            skip_call |= validateIdleDescriptorSet(dev_data, descriptor_sets[i], "vkFreeDescriptorSets");
6720405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
6721405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour    }
6722cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis
67239a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DESCRIPTOR_POOL_STATE *pool_state = GetDescriptorPoolState(dev_data, pool);
6724a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis    if (pool_state && !(VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT & pool_state->createInfo.flags)) {
6725cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis        // Can't Free from a NON_FREE pool
6726cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
67271c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis                             reinterpret_cast<uint64_t &>(pool), __LINE__, VALIDATION_ERROR_00922, "DS",
6728cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis                             "It is invalid to call vkFreeDescriptorSets() with a pool created without setting "
67291c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis                             "VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT. %s",
67301c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis                             validation_error_map[VALIDATION_ERROR_00922]);
6731cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    }
6732cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    return skip_call;
6733cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis}
6734cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis// Sets have been removed from the pool so update underlying state
6735cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlisstatic void PostCallRecordFreeDescriptorSets(layer_data *dev_data, VkDescriptorPool pool, uint32_t count,
6736cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis                                             const VkDescriptorSet *descriptor_sets) {
67379a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DESCRIPTOR_POOL_STATE *pool_state = GetDescriptorPoolState(dev_data, pool);
6738cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    // Update available descriptor sets in pool
6739cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    pool_state->availableSets += count;
6740cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis
6741cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    // For each freed descriptor add its resources back into the pool as available and remove from pool and setMap
6742cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    for (uint32_t i = 0; i < count; ++i) {
6743405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (descriptor_sets[i] != VK_NULL_HANDLE) {
6744405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            auto descriptor_set = dev_data->setMap[descriptor_sets[i]];
6745405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            uint32_t type_index = 0, descriptor_count = 0;
6746405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            for (uint32_t j = 0; j < descriptor_set->GetBindingCount(); ++j) {
6747405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour                type_index = static_cast<uint32_t>(descriptor_set->GetTypeFromIndex(j));
6748405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour                descriptor_count = descriptor_set->GetDescriptorCountFromIndex(j);
6749405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour                pool_state->availableDescriptorTypeCount[type_index] += descriptor_count;
6750405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            }
6751405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            freeDescriptorSet(dev_data, descriptor_set);
6752405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            pool_state->sets.erase(descriptor_set);
6753405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
6754cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    }
6755cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis}
67565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6757bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL FreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t count,
6758bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                  const VkDescriptorSet *pDescriptorSets) {
675956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
67605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Make sure that no sets being destroyed are in-flight
6761b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
676283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = PreCallValidateFreeDescriptorSets(dev_data, descriptorPool, count, pDescriptorSets);
6763b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
6764e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis
6765cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
67664a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.FreeDescriptorSets(device, descriptorPool, count, pDescriptorSets);
67675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6768b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
6769cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis        PostCallRecordFreeDescriptorSets(dev_data, descriptorPool, count, pDescriptorSets);
6770b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
67715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
67725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
67735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
67746b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis// TODO : This is a Proof-of-concept for core validation architecture
67756b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis//  Really we'll want to break out these functions to separate files but
67766b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis//  keeping it all together here to prove out design
67776b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis// PreCallValidate* handles validating all of the state prior to calling down chain to UpdateDescriptorSets()
67786b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlisstatic bool PreCallValidateUpdateDescriptorSets(layer_data *dev_data, uint32_t descriptorWriteCount,
67796b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                                const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
67806b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                                const VkCopyDescriptorSet *pDescriptorCopies) {
6781cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.update_descriptor_sets) return false;
67826b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // First thing to do is perform map look-ups.
67836b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // NOTE : UpdateDescriptorSets is somewhat unique in that it's operating on a number of DescriptorSets
67846b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    //  so we can't just do a single map look-up up-front, but do them individually in functions below
67856b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis
67866b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // Now make call(s) that validate state, but don't perform state updates in this function
67876b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // Note, here DescriptorSets is unique in that we don't yet have an instance. Using a helper function in the
67886b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    //  namespace which will parse params and make calls into specific class instances
6789104ab082916e41467ef60baaab7a5a8b2e02c59cTobin Ehlis    return cvdescriptorset::ValidateUpdateDescriptorSets(dev_data->report_data, dev_data, descriptorWriteCount, pDescriptorWrites,
6790104ab082916e41467ef60baaab7a5a8b2e02c59cTobin Ehlis                                                         descriptorCopyCount, pDescriptorCopies);
67916b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis}
67926b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis// PostCallRecord* handles recording state updates following call down chain to UpdateDescriptorSets()
67936b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlisstatic void PostCallRecordUpdateDescriptorSets(layer_data *dev_data, uint32_t descriptorWriteCount,
67946b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                               const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
67956b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                               const VkCopyDescriptorSet *pDescriptorCopies) {
6796104ab082916e41467ef60baaab7a5a8b2e02c59cTobin Ehlis    cvdescriptorset::PerformUpdateDescriptorSets(dev_data, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
67976b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                                 pDescriptorCopies);
67986b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis}
67995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6800bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL UpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount,
6801bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
6802bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkCopyDescriptorSet *pDescriptorCopies) {
68036b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // Only map look-up at top level is for device-level layer_data
680456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
6805b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
68066b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    bool skip_call = PreCallValidateUpdateDescriptorSets(dev_data, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
68076b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                                         pDescriptorCopies);
6808b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
68096b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    if (!skip_call) {
68104a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.UpdateDescriptorSets(device, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
68114a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                      pDescriptorCopies);
68126b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis        lock.lock();
68136b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis        // Since UpdateDescriptorSets() is void, nothing to check prior to updating state
68146b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis        PostCallRecordUpdateDescriptorSets(dev_data, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
68156b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                           pDescriptorCopies);
68165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
68175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
68185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6819bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL AllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pCreateInfo,
6820bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      VkCommandBuffer *pCommandBuffer) {
682156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
68224a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.AllocateCommandBuffers(device, pCreateInfo, pCommandBuffer);
68235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6824b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::unique_lock<std::mutex> lock(global_lock);
68259a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto pPool = GetCommandPoolNode(dev_data, pCreateInfo->commandPool);
6826cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes
6827cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes        if (pPool) {
682872d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis            for (uint32_t i = 0; i < pCreateInfo->commandBufferCount; i++) {
68295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // Add command buffer to its commandPool map
6830cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes                pPool->commandBuffers.push_back(pCommandBuffer[i]);
68315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                GLOBAL_CB_NODE *pCB = new GLOBAL_CB_NODE;
68325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // Add command buffer to map
68335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                dev_data->commandBufferMap[pCommandBuffer[i]] = pCB;
68345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                resetCB(dev_data, pCommandBuffer[i]);
68355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pCB->createInfo = *pCreateInfo;
68365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pCB->device = device;
68375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
68385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6839b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
68405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
68415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
68425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
68435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6844883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis// Add bindings between the given cmd buffer & framebuffer and the framebuffer's children
6845c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlisstatic void AddFramebufferBinding(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, FRAMEBUFFER_STATE *fb_state) {
68460245b74a083d2cb3b083571deb0fe13b4ab428a4Tobin Ehlis    addCommandBufferBinding(&fb_state->cb_bindings,
68470245b74a083d2cb3b083571deb0fe13b4ab428a4Tobin Ehlis                            {reinterpret_cast<uint64_t &>(fb_state->framebuffer), VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT},
68480245b74a083d2cb3b083571deb0fe13b4ab428a4Tobin Ehlis                            cb_state);
6849883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis    for (auto attachment : fb_state->attachments) {
6850883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        auto view_state = attachment.view_state;
6851883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        if (view_state) {
685203ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis            AddCommandBufferBindingImageView(dev_data, cb_state, view_state);
6853883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        }
68549a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto rp_state = GetRenderPassState(dev_data, fb_state->createInfo.renderPass);
6855883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        if (rp_state) {
6856883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis            addCommandBufferBinding(
6857883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis                &rp_state->cb_bindings,
6858883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis                {reinterpret_cast<uint64_t &>(rp_state->renderPass), VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT}, cb_state);
6859883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        }
6860883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis    }
6861883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis}
6862883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis
6863bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL BeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo) {
686483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
686556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6866b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
68675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Validate command buffer level
68689a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *cb_node = GetCBNode(dev_data, commandBuffer);
6869f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis    if (cb_node) {
68705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // This implicitly resets the Cmd Buffer so make sure any fence is done and then clear memory references
6871a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        if (dev_data->globalInFlightCmdBuffers.count(commandBuffer)) {
687283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |=
6873a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
68744527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                        (uint64_t)commandBuffer, __LINE__, VALIDATION_ERROR_00104, "MEM",
6875d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen                        "Calling vkBeginCommandBuffer() on active command buffer 0x%p before it has completed. "
68764527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                        "You must check command buffer fence before this call. %s",
68774527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                        commandBuffer, validation_error_map[VALIDATION_ERROR_00104]);
68785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6879f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        clear_cmd_buf_and_mem_references(dev_data, cb_node);
6880f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        if (cb_node->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
68815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Secondary Command Buffer
68825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            const VkCommandBufferInheritanceInfo *pInfo = pBeginInfo->pInheritanceInfo;
68835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!pInfo) {
688483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                skip_call |=
68855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
68864527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            reinterpret_cast<uint64_t>(commandBuffer), __LINE__, VALIDATION_ERROR_00106, "DS",
6887bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "vkBeginCommandBuffer(): Secondary Command Buffer (0x%p) must have inheritance info. %s", commandBuffer,
6888bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            validation_error_map[VALIDATION_ERROR_00106]);
68895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else {
68905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (pBeginInfo->flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT) {
68912c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                    // Object_tracker makes sure these objects are valid
68922c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                    assert(pInfo->renderPass);
68932c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                    assert(pInfo->framebuffer);
68942c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                    string errorString = "";
68959a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto framebuffer = GetFramebufferState(dev_data, pInfo->framebuffer);
68962c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                    if (framebuffer) {
68972c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                        if ((framebuffer->createInfo.renderPass != pInfo->renderPass) &&
68982c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                            !verify_renderpass_compatibility(dev_data, framebuffer->renderPassCreateInfo.ptr(),
68999a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                                                             GetRenderPassState(dev_data, pInfo->renderPass)->createInfo.ptr(),
69002c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                             errorString)) {
69012c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                            // renderPass that framebuffer was created with must be compatible with local renderPass
69022c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
69032c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
69042c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                 reinterpret_cast<uint64_t>(commandBuffer), __LINE__, VALIDATION_ERROR_00112, "DS",
69052c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                 "vkBeginCommandBuffer(): Secondary Command "
6906cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                 "Buffer (0x%p) renderPass (0x%" PRIxLEAST64
6907cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                 ") is incompatible w/ framebuffer "
69082c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                 "(0x%" PRIxLEAST64 ") w/ render pass (0x%" PRIxLEAST64 ") due to: %s. %s",
69092c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                 commandBuffer, reinterpret_cast<const uint64_t &>(pInfo->renderPass),
69102c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                 reinterpret_cast<const uint64_t &>(pInfo->framebuffer),
69112c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                 reinterpret_cast<uint64_t &>(framebuffer->createInfo.renderPass),
69122c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                 errorString.c_str(), validation_error_map[VALIDATION_ERROR_00112]);
69135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        }
69142c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                        // Connect this framebuffer and its children to this cmdBuffer
69152c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                        AddFramebufferBinding(dev_data, cb_node, framebuffer);
69165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
69175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
69184527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                if ((pInfo->occlusionQueryEnable == VK_FALSE || dev_data->enabled_features.occlusionQueryPrecise == VK_FALSE) &&
69195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    (pInfo->queryFlags & VK_QUERY_CONTROL_PRECISE_BIT)) {
692083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
692183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                         VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t>(commandBuffer),
69224527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                         __LINE__, VALIDATION_ERROR_00107, "DS",
692383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                         "vkBeginCommandBuffer(): Secondary Command Buffer (0x%p) must not have "
692483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                                         "VK_QUERY_CONTROL_PRECISE_BIT if occulusionQuery is disabled or the device does not "
69254527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                         "support precise occlusion queries. %s",
69264527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                                         commandBuffer, validation_error_map[VALIDATION_ERROR_00107]);
69275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
69285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
69295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (pInfo && pInfo->renderPass != VK_NULL_HANDLE) {
69309a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto renderPass = GetRenderPassState(dev_data, pInfo->renderPass);
693116387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                if (renderPass) {
6932fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes                    if (pInfo->subpass >= renderPass->createInfo.subpassCount) {
693383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                        skip_call |= log_msg(
6934bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6935bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            (uint64_t)commandBuffer, __LINE__, VALIDATION_ERROR_00111, "DS",
69364527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            "vkBeginCommandBuffer(): Secondary Command Buffers (0x%p) must have a subpass index (%d) "
69374527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            "that is less than the number of subpasses (%d). %s",
69384527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            commandBuffer, pInfo->subpass, renderPass->createInfo.subpassCount,
69394527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            validation_error_map[VALIDATION_ERROR_00111]);
69405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
69415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
69425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
69435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6944f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        if (CB_RECORDING == cb_node->state) {
6945cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            skip_call |=
6946cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6947cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        (uint64_t)commandBuffer, __LINE__, VALIDATION_ERROR_00103, "DS",
6948cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "vkBeginCommandBuffer(): Cannot call Begin on command buffer (0x%p"
6949cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        ") in the RECORDING state. Must first call vkEndCommandBuffer(). %s",
6950cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        commandBuffer, validation_error_map[VALIDATION_ERROR_00103]);
6951347d4d3139a1e743ed85bd375c20fd35bbe68d74Chris Forbes        } else if (CB_RECORDED == cb_node->state || (CB_INVALID == cb_node->state && CMD_END == cb_node->last_cmd)) {
6952f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            VkCommandPool cmdPool = cb_node->createInfo.commandPool;
69539a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pPool = GetCommandPoolNode(dev_data, cmdPool);
6954cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes            if (!(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT & pPool->createFlags)) {
695583b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                skip_call |=
69565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
69574527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            (uint64_t)commandBuffer, __LINE__, VALIDATION_ERROR_00105, "DS",
6958226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                            "Call to vkBeginCommandBuffer() on command buffer (0x%p"
6959414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                            ") attempts to implicitly reset cmdBuffer created from command pool (0x%" PRIxLEAST64
69604527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            ") that does NOT have the VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT bit set. %s",
69614527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            commandBuffer, (uint64_t)cmdPool, validation_error_map[VALIDATION_ERROR_00105]);
69625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
69635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            resetCB(dev_data, commandBuffer);
69645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
69655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Set updated state here in case implicit reset occurs above
6966f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        cb_node->state = CB_RECORDING;
6967f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        cb_node->beginInfo = *pBeginInfo;
6968f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        if (cb_node->beginInfo.pInheritanceInfo) {
6969f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->inheritanceInfo = *(cb_node->beginInfo.pInheritanceInfo);
6970f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->beginInfo.pInheritanceInfo = &cb_node->inheritanceInfo;
6971888e1d268098177fde4a2263e3d7b7cc415f1debMark Young            // If we are a secondary command-buffer and inheriting.  Update the items we should inherit.
6972f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            if ((cb_node->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) &&
6973f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                (cb_node->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
69749a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                cb_node->activeRenderPass = GetRenderPassState(dev_data, cb_node->beginInfo.pInheritanceInfo->renderPass);
6975f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                cb_node->activeSubpass = cb_node->beginInfo.pInheritanceInfo->subpass;
6976350841afb70bf8dcfc3c6ec6b66f0aaa639553a3Tobin Ehlis                cb_node->activeFramebuffer = cb_node->beginInfo.pInheritanceInfo->framebuffer;
6977f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                cb_node->framebuffers.insert(cb_node->beginInfo.pInheritanceInfo->framebuffer);
6978888e1d268098177fde4a2263e3d7b7cc415f1debMark Young            }
69795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
69805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6981b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
698283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (skip_call) {
69835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return VK_ERROR_VALIDATION_FAILED_EXT;
69845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
69854a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.BeginCommandBuffer(commandBuffer, pBeginInfo);
6986400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis
69875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
69885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
69895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
699089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL EndCommandBuffer(VkCommandBuffer commandBuffer) {
699183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
69925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_SUCCESS;
699356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6994b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
69959a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
69965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
69974527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton        if ((VK_COMMAND_BUFFER_LEVEL_PRIMARY == pCB->createInfo.level) ||
69984527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
6999fd61966f8d41b5bce15620b70563b7864cbb28feCody Northrop            // This needs spec clarification to update valid usage, see comments in PR:
7000fd61966f8d41b5bce15620b70563b7864cbb28feCody Northrop            // https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/pull/516#discussion_r63013756
7001ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen            skip_call |= insideRenderPass(dev_data, pCB, "vkEndCommandBuffer()", VALIDATION_ERROR_00123);
7002fd61966f8d41b5bce15620b70563b7864cbb28feCody Northrop        }
700329f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_END, "vkEndCommandBuffer()");
70041ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_END);
70055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto query : pCB->activeQueries) {
7006df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip_call |=
7007df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
7008df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        reinterpret_cast<uint64_t>(commandBuffer), __LINE__, VALIDATION_ERROR_00124, "DS",
7009df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        "Ending command buffer with in progress query: queryPool 0x%" PRIx64 ", index %d. %s",
7010df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        (uint64_t)(query.pool), query.index, validation_error_map[VALIDATION_ERROR_00124]);
70115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
70125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
701383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (!skip_call) {
7014b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
70154a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.EndCommandBuffer(commandBuffer);
7016b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
70175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (VK_SUCCESS == result) {
70185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pCB->state = CB_RECORDED;
70195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Reset CB status flags
70205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pCB->status = 0;
70215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
70225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
70235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        result = VK_ERROR_VALIDATION_FAILED_EXT;
70245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7025b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
70265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
70275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
70285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7029bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL ResetCommandBuffer(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags) {
7030bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    bool skip_call = false;
703156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7032b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
70339a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
70345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkCommandPool cmdPool = pCB->createInfo.commandPool;
70359a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pPool = GetCommandPoolNode(dev_data, cmdPool);
7036cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes    if (!(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT & pPool->createFlags)) {
7037bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
70384527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                             (uint64_t)commandBuffer, __LINE__, VALIDATION_ERROR_00093, "DS",
7039226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                             "Attempt to reset command buffer (0x%p) created from command pool (0x%" PRIxLEAST64
70404527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                             ") that does NOT have the VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT bit set. %s",
70414527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                             commandBuffer, (uint64_t)cmdPool, validation_error_map[VALIDATION_ERROR_00093]);
70425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7043cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis    skip_call |= checkCommandBufferInFlight(dev_data, pCB, "reset", VALIDATION_ERROR_00092);
7044b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7045cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
70464a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.ResetCommandBuffer(commandBuffer, flags);
70475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
7048b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
7049a964cad279f9749cd9ebfc7555247ff3bff26d53Chris Forbes        dev_data->globalInFlightCmdBuffers.erase(commandBuffer);
70505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        resetCB(dev_data, commandBuffer);
7051b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
70525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
70535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
70545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
705593c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski
7056bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBindPipeline(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
7057bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           VkPipeline pipeline) {
7058e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis    bool skip = false;
705956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7060b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
70619a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
7062e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis    if (cb_state) {
7063baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdBindPipeline()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
7064baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                      VALIDATION_ERROR_00603);
706529f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip |= ValidateCmd(dev_data, cb_state, CMD_BINDPIPELINE, "vkCmdBindPipeline()");
70661ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(cb_state, CMD_BINDPIPELINE);
7067e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        if ((VK_PIPELINE_BIND_POINT_COMPUTE == pipelineBindPoint) && (cb_state->activeRenderPass)) {
7068e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            skip |=
70695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
70705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        (uint64_t)pipeline, __LINE__, DRAWSTATE_INVALID_RENDERPASS_CMD, "DS",
7071414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                        "Incorrectly binding compute pipeline (0x%" PRIxLEAST64 ") during active RenderPass (0x%" PRIxLEAST64 ")",
7072e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis                        (uint64_t)pipeline, (uint64_t)cb_state->activeRenderPass->renderPass);
70735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
70744527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton        // TODO: VALIDATION_ERROR_00594 VALIDATION_ERROR_00596
70755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7076e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        PIPELINE_STATE *pipe_state = getPipelineState(dev_data, pipeline);
7077e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        if (pipe_state) {
7078e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            cb_state->lastBound[pipelineBindPoint].pipeline_state = pipe_state;
7079e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            set_cb_pso_status(cb_state, pipe_state);
7080e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            set_pipeline_state(pipe_state);
7081daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski            skip |= validate_dual_src_blend_feature(dev_data, pipe_state);
70825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
7083e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
70844527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            (uint64_t)pipeline, __LINE__, VALIDATION_ERROR_00600, "DS",
70854527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            "Attempt to bind Pipeline 0x%" PRIxLEAST64 " that doesn't exist! %s", (uint64_t)(pipeline),
70864527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            validation_error_map[VALIDATION_ERROR_00600]);
7087e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        }
7088e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        addCommandBufferBinding(&pipe_state->cb_bindings,
7089e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis                                {reinterpret_cast<uint64_t &>(pipeline), VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT}, cb_state);
7090e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        if (VK_PIPELINE_BIND_POINT_GRAPHICS == pipelineBindPoint) {
7091e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            // Add binding for child renderpass
70929a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto rp_state = GetRenderPassState(dev_data, pipe_state->graphicsPipelineCI.renderPass);
7093e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            if (rp_state) {
7094e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis                addCommandBufferBinding(
7095e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis                    &rp_state->cb_bindings,
7096e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis                    {reinterpret_cast<uint64_t &>(rp_state->renderPass), VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT}, cb_state);
7097e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            }
70985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
70995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7100b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7101cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdBindPipeline(commandBuffer, pipelineBindPoint, pipeline);
71025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
71035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7104bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetViewport(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount,
7105bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                          const VkViewport *pViewports) {
710683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
710756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7108b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
71099a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
71105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
7111baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip_call |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetViewport()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_01446);
711229f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETVIEWPORTSTATE, "vkCmdSetViewport()");
71131ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETVIEWPORTSTATE);
7114bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pCB->viewportMask |= ((1u << viewportCount) - 1u) << firstViewport;
71155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7116b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7117cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetViewport(commandBuffer, firstViewport, viewportCount, pViewports);
71185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
71195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7120bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetScissor(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount,
7121bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         const VkRect2D *pScissors) {
712283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
712356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7124b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
71259a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
71265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
7127baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip_call |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetScissor()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_01495);
712829f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETSCISSORSTATE, "vkCmdSetScissor()");
71291ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETSCISSORSTATE);
7130bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pCB->scissorMask |= ((1u << scissorCount) - 1u) << firstScissor;
71315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7132b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7133cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetScissor(commandBuffer, firstScissor, scissorCount, pScissors);
71345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
71355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
713689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth) {
7137a27508babf63d50aea75883a3702979193c23683Mark Young    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) {
7142baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip_call |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetLineWidth()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_01480);
714329f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETLINEWIDTHSTATE, "vkCmdSetLineWidth()");
71441ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETLINEWIDTHSTATE);
71455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_LINE_WIDTH_SET;
7146a27508babf63d50aea75883a3702979193c23683Mark Young
71474c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis        PIPELINE_STATE *pPipeTrav = pCB->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].pipeline_state;
7148a27508babf63d50aea75883a3702979193c23683Mark Young        if (pPipeTrav != NULL && !isDynamic(pPipeTrav, VK_DYNAMIC_STATE_LINE_WIDTH)) {
7149df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip_call |=
7150df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
7151df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        reinterpret_cast<uint64_t>(commandBuffer), __LINE__, VALIDATION_ERROR_01476, "DS",
7152df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        "vkCmdSetLineWidth called but pipeline was created without VK_DYNAMIC_STATE_LINE_WIDTH "
7153df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        "flag.  This is undefined behavior and could be ignored. %s",
7154df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        validation_error_map[VALIDATION_ERROR_01476]);
7155a27508babf63d50aea75883a3702979193c23683Mark Young        } else {
7156df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip_call |= verifyLineWidth(dev_data, DRAWSTATE_INVALID_SET, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
7157df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                         reinterpret_cast<uint64_t &>(commandBuffer), lineWidth);
7158a27508babf63d50aea75883a3702979193c23683Mark Young        }
71595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7160b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7161cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetLineWidth(commandBuffer, lineWidth);
71625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
71635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7164bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetDepthBias(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp,
7165bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           float depthBiasSlopeFactor) {
716683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
716756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7168b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
71699a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
71705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
7171baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip_call |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetDepthBias()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_01485);
717229f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETDEPTHBIASSTATE, "vkCmdSetDepthBias()");
7173434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski        if ((depthBiasClamp != 0.0) && (!dev_data->enabled_features.depthBiasClamp)) {
7174df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip_call |=
7175df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
7176df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        reinterpret_cast<uint64_t>(commandBuffer), __LINE__, VALIDATION_ERROR_01482, "DS",
7177df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        "vkCmdSetDepthBias(): the depthBiasClamp device feature is disabled: the depthBiasClamp "
7178df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        "parameter must be set to 0.0. %s",
7179df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        validation_error_map[VALIDATION_ERROR_01482]);
7180434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski        }
7181434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski        if (!skip_call) {
7182434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski            UpdateCmdBufferLastCmd(pCB, CMD_SETDEPTHBIASSTATE);
7183434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski            pCB->status |= CBSTATUS_DEPTH_BIAS_SET;
7184434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski        }
71855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7186b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
718783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (!skip_call)
71884a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdSetDepthBias(commandBuffer, depthBiasConstantFactor, depthBiasClamp, depthBiasSlopeFactor);
71895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
71905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
719189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdSetBlendConstants(VkCommandBuffer commandBuffer, const float blendConstants[4]) {
719283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
719356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7194b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
71959a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
71965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
7197baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip_call |=
7198baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt            ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetBlendConstants()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_01553);
719929f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETBLENDSTATE, "vkCmdSetBlendConstants()");
72001ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETBLENDSTATE);
72013d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        pCB->status |= CBSTATUS_BLEND_CONSTANTS_SET;
72025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7203b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7204cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetBlendConstants(commandBuffer, blendConstants);
72055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
72065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7207bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetDepthBounds(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds) {
720883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
720956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7210b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
72119a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
72125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
7213baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip_call |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetDepthBounds()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_01509);
721429f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETDEPTHBOUNDSSTATE, "vkCmdSetDepthBounds()");
72151ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETDEPTHBOUNDSSTATE);
72165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_DEPTH_BOUNDS_SET;
72175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7218b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7219cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetDepthBounds(commandBuffer, minDepthBounds, maxDepthBounds);
72205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
72215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7222bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetStencilCompareMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask,
7223bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                    uint32_t compareMask) {
722483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
722556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7226b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
72279a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
72285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
7229baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip_call |=
7230baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt            ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetStencilCompareMask()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_01519);
723129f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETSTENCILREADMASKSTATE, "vkCmdSetStencilCompareMask()");
72321ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETSTENCILREADMASKSTATE);
72335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_STENCIL_READ_MASK_SET;
72345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7235b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7236cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetStencilCompareMask(commandBuffer, faceMask, compareMask);
72375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
72385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7239bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetStencilWriteMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask) {
724083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
724156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7242b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
72439a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
72445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
7245baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip_call |=
7246baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt            ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetStencilWriteMask()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_01525);
724729f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETSTENCILWRITEMASKSTATE, "vkCmdSetStencilWriteMask()");
72481ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETSTENCILWRITEMASKSTATE);
72495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_STENCIL_WRITE_MASK_SET;
72505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7251b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7252cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetStencilWriteMask(commandBuffer, faceMask, writeMask);
72535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
72545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7255bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetStencilReference(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference) {
725683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
725756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7258b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
72599a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
72605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
7261baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip_call |=
7262baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt            ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetStencilReference()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_01531);
726329f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETSTENCILREFERENCESTATE, "vkCmdSetStencilReference()");
72641ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETSTENCILREFERENCESTATE);
72655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_STENCIL_REFERENCE_SET;
72665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7267b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7268cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetStencilReference(commandBuffer, faceMask, reference);
72695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
72705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7271bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBindDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
7272bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 VkPipelineLayout layout, uint32_t firstSet, uint32_t setCount,
7273bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkDescriptorSet *pDescriptorSets, uint32_t dynamicOffsetCount,
7274bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const uint32_t *pDynamicOffsets) {
7275946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
727656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7277b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7278946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
7279946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (cb_state) {
7280baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdBindDescriptorSets()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
7281baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                      VALIDATION_ERROR_00985);
7282946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_state, CMD_BINDDESCRIPTORSETS, "vkCmdBindDescriptorSets()");
7283ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        // Track total count of dynamic descriptor types to make sure we have an offset for each one
7284946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        uint32_t total_dynamic_descriptors = 0;
7285946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        string error_string = "";
7286946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        uint32_t last_set_index = firstSet + setCount - 1;
7287946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        if (last_set_index >= cb_state->lastBound[pipelineBindPoint].boundDescriptorSets.size()) {
7288946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            cb_state->lastBound[pipelineBindPoint].boundDescriptorSets.resize(last_set_index + 1);
7289946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            cb_state->lastBound[pipelineBindPoint].dynamicOffsets.resize(last_set_index + 1);
7290946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        }
7291946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        auto old_final_bound_set = cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[last_set_index];
7292ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        auto pipeline_layout = getPipelineLayout(dev_data, layout);
7293ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        for (uint32_t set_idx = 0; set_idx < setCount; set_idx++) {
7294ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            cvdescriptorset::DescriptorSet *descriptor_set = GetSetNode(dev_data, pDescriptorSets[set_idx]);
7295ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            if (descriptor_set) {
7296946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                cb_state->lastBound[pipelineBindPoint].pipeline_layout = *pipeline_layout;
7297946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[set_idx + firstSet] = descriptor_set;
7298946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT,
7299946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[set_idx], __LINE__,
7300946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                DRAWSTATE_NONE, "DS", "Descriptor Set 0x%" PRIxLEAST64 " bound on pipeline %s",
7301946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                (uint64_t)pDescriptorSets[set_idx], string_VkPipelineBindPoint(pipelineBindPoint));
7302ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                if (!descriptor_set->IsUpdated() && (descriptor_set->GetTotalDescriptorCount() != 0)) {
7303946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
7304946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[set_idx], __LINE__,
7305946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS",
7306946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    "Descriptor Set 0x%" PRIxLEAST64
7307946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    " bound but it was never updated. You may want to either update it or not bind it.",
7308946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    (uint64_t)pDescriptorSets[set_idx]);
7309ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                }
7310ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                // Verify that set being bound is compatible with overlapping setLayout of pipelineLayout
7311946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                if (!verify_set_layout_compatibility(dev_data, descriptor_set, pipeline_layout, set_idx + firstSet, error_string)) {
7312946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
7313946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[set_idx], __LINE__,
7314946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    VALIDATION_ERROR_00974, "DS",
7315946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    "descriptorSet #%u being bound is not compatible with overlapping descriptorSetLayout "
7316946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    "at index %u of pipelineLayout 0x%" PRIxLEAST64 " due to: %s. %s",
7317946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    set_idx, set_idx + firstSet, reinterpret_cast<uint64_t &>(layout), error_string.c_str(),
7318946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    validation_error_map[VALIDATION_ERROR_00974]);
73195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
7320ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski
7321946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                auto set_dynamic_descriptor_count = descriptor_set->GetDynamicDescriptorCount();
7322ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski
7323946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                cb_state->lastBound[pipelineBindPoint].dynamicOffsets[firstSet + set_idx].clear();
7324ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski
7325946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                if (set_dynamic_descriptor_count) {
7326ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                    // First make sure we won't overstep bounds of pDynamicOffsets array
7327946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    if ((total_dynamic_descriptors + set_dynamic_descriptor_count) > dynamicOffsetCount) {
7328946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
7329946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                        VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[set_idx],
7330946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                        __LINE__, DRAWSTATE_INVALID_DYNAMIC_OFFSET_COUNT, "DS",
7331946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                        "descriptorSet #%u (0x%" PRIxLEAST64
7332946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                        ") requires %u dynamicOffsets, but only %u dynamicOffsets are left in pDynamicOffsets "
7333946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                        "array. There must be one dynamic offset for each dynamic descriptor being bound.",
7334946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                        set_idx, (uint64_t)pDescriptorSets[set_idx], descriptor_set->GetDynamicDescriptorCount(),
7335946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                        (dynamicOffsetCount - total_dynamic_descriptors));
7336ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                    } else {  // Validate and store dynamic offsets with the set
7337ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                        // Validate Dynamic Offset Minimums
7338946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        uint32_t cur_dyn_offset = total_dynamic_descriptors;
7339ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                        for (uint32_t d = 0; d < descriptor_set->GetTotalDescriptorCount(); d++) {
7340ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            if (descriptor_set->GetTypeFromGlobalIndex(d) == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) {
7341ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                if (vk_safe_modulo(
7342ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        pDynamicOffsets[cur_dyn_offset],
7343ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment) != 0) {
7344946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    skip |= log_msg(
7345ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
7346ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, VALIDATION_ERROR_00978, "DS",
7347ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        "vkCmdBindDescriptorSets(): pDynamicOffsets[%d] is %d but must be a multiple of "
7348ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        "device limit minUniformBufferOffsetAlignment 0x%" PRIxLEAST64 ". %s",
7349ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        cur_dyn_offset, pDynamicOffsets[cur_dyn_offset],
7350ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment,
7351ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        validation_error_map[VALIDATION_ERROR_00978]);
7352ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                }
7353ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                cur_dyn_offset++;
7354ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            } else if (descriptor_set->GetTypeFromGlobalIndex(d) == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
7355ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                if (vk_safe_modulo(
7356ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        pDynamicOffsets[cur_dyn_offset],
7357ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        dev_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment) != 0) {
7358946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    skip |= log_msg(
7359ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
7360ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, VALIDATION_ERROR_00978, "DS",
7361ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        "vkCmdBindDescriptorSets(): pDynamicOffsets[%d] is %d but must be a multiple of "
7362ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        "device limit minStorageBufferOffsetAlignment 0x%" PRIxLEAST64 ". %s",
7363ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        cur_dyn_offset, pDynamicOffsets[cur_dyn_offset],
7364ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        dev_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment,
7365ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        validation_error_map[VALIDATION_ERROR_00978]);
7366ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                }
7367ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                cur_dyn_offset++;
7368ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            }
736972d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                        }
7370ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski
7371946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        cb_state->lastBound[pipelineBindPoint].dynamicOffsets[firstSet + set_idx] =
7372946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            std::vector<uint32_t>(pDynamicOffsets + total_dynamic_descriptors,
7373946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                                  pDynamicOffsets + total_dynamic_descriptors + set_dynamic_descriptor_count);
7374ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                        // Keep running total of dynamic descriptor count to verify at the end
7375946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        total_dynamic_descriptors += set_dynamic_descriptor_count;
737672d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                    }
737772d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                }
7378ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            } else {
7379946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                skip |= log_msg(
7380ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
7381ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                    (uint64_t)pDescriptorSets[set_idx], __LINE__, DRAWSTATE_INVALID_SET, "DS",
7382ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                    "Attempt to bind descriptor set 0x%" PRIxLEAST64 " that doesn't exist!", (uint64_t)pDescriptorSets[set_idx]);
7383ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            }
7384946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            UpdateCmdBufferLastCmd(cb_state, CMD_BINDDESCRIPTORSETS);
7385ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            // For any previously bound sets, need to set them to "invalid" if they were disturbed by this update
7386ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            if (firstSet > 0) {  // Check set #s below the first bound set
7387ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                for (uint32_t i = 0; i < firstSet; ++i) {
7388946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    if (cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[i] &&
7389946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        !verify_set_layout_compatibility(dev_data, cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[i],
7390946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                                         pipeline_layout, i, error_string)) {
7391946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        skip |= log_msg(
7392ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
7393ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
7394946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            (uint64_t)cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[i], __LINE__, DRAWSTATE_NONE, "DS",
7395ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            "DescriptorSet 0x%" PRIxLEAST64
7396ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            " previously bound as set #%u was disturbed by newly bound pipelineLayout (0x%" PRIxLEAST64 ")",
7397946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            (uint64_t)cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[i], i, (uint64_t)layout);
7398946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[i] = VK_NULL_HANDLE;
73995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
74005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
74015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
7402ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            // Check if newly last bound set invalidates any remaining bound sets
7403946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            if ((cb_state->lastBound[pipelineBindPoint].boundDescriptorSets.size() - 1) > (last_set_index)) {
7404946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                if (old_final_bound_set &&
7405946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    !verify_set_layout_compatibility(dev_data, old_final_bound_set, pipeline_layout, last_set_index,
7406946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                                     error_string)) {
7407946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    auto old_set = old_final_bound_set->GetSet();
7408946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
7409946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, reinterpret_cast<uint64_t &>(old_set), __LINE__,
7410946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    DRAWSTATE_NONE, "DS", "DescriptorSet 0x%" PRIxLEAST64
7411946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                                          " previously bound as set #%u is incompatible with set 0x%" PRIxLEAST64
7412946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                                          " newly bound as set #%u so set #%u and any subsequent sets were "
7413946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                                          "disturbed by newly bound pipelineLayout (0x%" PRIxLEAST64 ")",
7414946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    reinterpret_cast<uint64_t &>(old_set), last_set_index,
7415946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    (uint64_t)cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[last_set_index],
7416946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    last_set_index, last_set_index + 1, (uint64_t)layout);
7417946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    cb_state->lastBound[pipelineBindPoint].boundDescriptorSets.resize(last_set_index + 1);
7418ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                }
7419787f29d93dee194c015789cf61c079504c980572Tobin Ehlis            }
7420ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        }
7421ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        //  dynamicOffsetCount must equal the total number of dynamic descriptors in the sets being bound
7422946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        if (total_dynamic_descriptors != dynamicOffsetCount) {
7423946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
7424946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            (uint64_t)commandBuffer, __LINE__, VALIDATION_ERROR_00975, "DS",
7425946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            "Attempting to bind %u descriptorSets with %u dynamic descriptors, but dynamicOffsetCount "
7426946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            "is %u. It should exactly match the number of dynamic descriptors. %s",
7427946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            setCount, total_dynamic_descriptors, dynamicOffsetCount, validation_error_map[VALIDATION_ERROR_00975]);
74285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
74295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7430b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7431946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip)
74324a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdBindDescriptorSets(commandBuffer, pipelineBindPoint, layout, firstSet, setCount,
74334a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                       pDescriptorSets, dynamicOffsetCount, pDynamicOffsets);
74345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
74355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7436bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBindIndexBuffer(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
7437bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              VkIndexType indexType) {
7438946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
743956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7440593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis    // TODO : Somewhere need to verify that IBs have correct usage state flagged
7441b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7442b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski
74439a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto buffer_state = GetBufferState(dev_data, buffer);
74449a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
74455cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (cb_node && buffer_state) {
7446baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_node, "vkCmdBindIndexBuffer()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_01357);
7447946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_node, CMD_BINDINDEXBUFFER, "vkCmdBindIndexBuffer()");
7448946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateMemoryIsBoundToBuffer(dev_data, buffer_state, "vkCmdBindIndexBuffer()", VALIDATION_ERROR_02543);
7449ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        std::function<bool()> function = [=]() {
7450ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            return ValidateBufferMemoryIsValid(dev_data, buffer_state, "vkCmdBindIndexBuffer()");
7451ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        };
7452ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        cb_node->validate_functions.push_back(function);
7453ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        UpdateCmdBufferLastCmd(cb_node, CMD_BINDINDEXBUFFER);
7454ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        VkDeviceSize offset_align = 0;
7455ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        switch (indexType) {
7456ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            case VK_INDEX_TYPE_UINT16:
7457ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                offset_align = 2;
7458ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                break;
7459ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            case VK_INDEX_TYPE_UINT32:
7460ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                offset_align = 4;
7461ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                break;
7462ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            default:
7463ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                // ParamChecker should catch bad enum, we'll also throw alignment error below if offset_align stays 0
7464ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                break;
74655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7466ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        if (!offset_align || (offset % offset_align)) {
7467df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
7468df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            reinterpret_cast<uint64_t>(commandBuffer), __LINE__, DRAWSTATE_VTX_INDEX_ALIGNMENT_ERROR, "DS",
7469946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            "vkCmdBindIndexBuffer() offset (0x%" PRIxLEAST64 ") does not fall on alignment (%s) boundary.", offset,
7470946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            string_VkIndexType(indexType));
7471ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        }
7472ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        cb_node->status |= CBSTATUS_INDEX_BUFFER_BOUND;
7473ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
7474ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
74755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7476b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7477946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdBindIndexBuffer(commandBuffer, buffer, offset, indexType);
74785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
74795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
74805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisvoid updateResourceTracking(GLOBAL_CB_NODE *pCB, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer *pBuffers) {
74815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t end = firstBinding + bindingCount;
74825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB->currentDrawData.buffers.size() < end) {
74835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->currentDrawData.buffers.resize(end);
74845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
74855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < bindingCount; ++i) {
74865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->currentDrawData.buffers[i + firstBinding] = pBuffers[i];
74875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
74885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
74895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7490e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic inline void updateResourceTrackingOnDraw(GLOBAL_CB_NODE *pCB) { pCB->drawData.push_back(pCB->currentDrawData); }
74915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7492bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBindVertexBuffers(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount,
7493bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkBuffer *pBuffers, const VkDeviceSize *pOffsets) {
7494946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
749556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7496593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis    // TODO : Somewhere need to verify that VBs have correct usage state flagged
7497b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7498b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski
74999a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
75009f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis    if (cb_node) {
7501baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_node, "vkCmdBindVertexBuffers()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_01423);
7502baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmd(dev_data, cb_node, CMD_BINDVERTEXBUFFER, "vkCmdBindVertexBuffers()");
7503ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        for (uint32_t i = 0; i < bindingCount; ++i) {
7504ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            auto buffer_state = GetBufferState(dev_data, pBuffers[i]);
7505ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            assert(buffer_state);
7506946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            skip |= ValidateMemoryIsBoundToBuffer(dev_data, buffer_state, "vkCmdBindVertexBuffers()", VALIDATION_ERROR_02546);
7507ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            std::function<bool()> function = [=]() {
7508ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                return ValidateBufferMemoryIsValid(dev_data, buffer_state, "vkCmdBindVertexBuffers()");
7509ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            };
7510ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            cb_node->validate_functions.push_back(function);
75115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7512ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        UpdateCmdBufferLastCmd(cb_node, CMD_BINDVERTEXBUFFER);
7513ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        updateResourceTracking(cb_node, firstBinding, bindingCount, pBuffers);
75145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
75157828015969ab31ee01d597f0288cbb124b637fcdMark Lobodzinski        assert(0);
75165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7517b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7518946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdBindVertexBuffers(commandBuffer, firstBinding, bindingCount, pBuffers, pOffsets);
75195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
75205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
752125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// Expects global_lock to be held by caller
75225569d6457ac22e7d245f3cdee045e71ffbc8b06eTobin Ehlisstatic void MarkStoreImagesAndBuffersAsWritten(layer_data *dev_data, GLOBAL_CB_NODE *pCB) {
75237a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis    for (auto imageView : pCB->updateImages) {
75249a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto view_state = GetImageViewState(dev_data, imageView);
7525cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!view_state) continue;
7526249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis
75279a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto image_state = GetImageState(dev_data, view_state->create_info.image);
75281facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        assert(image_state);
7529e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
75301facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            SetImageMemoryValid(dev_data, image_state, true);
7531e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
75327a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        };
75337a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        pCB->validate_functions.push_back(function);
75347a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis    }
75357a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis    for (auto buffer : pCB->updateBuffers) {
75369a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto buffer_state = GetBufferState(dev_data, buffer);
75375cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        assert(buffer_state);
7538e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
75395cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            SetBufferMemoryValid(dev_data, buffer_state, true);
7540e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
75417a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        };
75427a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        pCB->validate_functions.push_back(function);
75435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
75445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
75455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7546ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis// Generic function to handle validation for all CmdDraw* type functions
7547ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool ValidateCmdDrawType(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed, VkPipelineBindPoint bind_point,
7548baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                CMD_TYPE cmd_type, GLOBAL_CB_NODE **cb_state, const char *caller, VkQueueFlags queue_flags,
7549baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                UNIQUE_VALIDATION_ERROR_CODE queue_flag_code, UNIQUE_VALIDATION_ERROR_CODE msg_code,
7550baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                UNIQUE_VALIDATION_ERROR_CODE const dynamic_state_msg_code) {
755158b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    bool skip = false;
75529a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *cb_state = GetCBNode(dev_data, cmd_buffer);
755358b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    if (*cb_state) {
7554baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, *cb_state, caller, queue_flags, queue_flag_code);
7555ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis        skip |= ValidateCmd(dev_data, *cb_state, cmd_type, caller);
75564f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes        skip |= ValidateDrawState(dev_data, *cb_state, indexed, bind_point, caller, dynamic_state_msg_code);
755725d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis        skip |= (VK_PIPELINE_BIND_POINT_GRAPHICS == bind_point) ? outsideRenderPass(dev_data, *cb_state, caller, msg_code)
755825d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis                                                                : insideRenderPass(dev_data, *cb_state, caller, msg_code);
755958b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    }
756058b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    return skip;
756158b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis}
756258b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis
756325d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis// Generic function to handle state update for all CmdDraw* and CmdDispatch* type functions
7564ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void UpdateStateCmdDrawDispatchType(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
7565ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                           CMD_TYPE cmd_type) {
7566ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateDrawState(dev_data, cb_state, bind_point);
75672f921d33544c162dcb726fc3c7b915e89c02ff24Tobin Ehlis    MarkStoreImagesAndBuffersAsWritten(dev_data, cb_state);
75681ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis    UpdateCmdBufferLastCmd(cb_state, cmd_type);
756925d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis}
757025d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis
7571ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis// Generic function to handle state update for all CmdDraw* type functions
7572ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void UpdateStateCmdDrawType(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
7573ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                   CMD_TYPE cmd_type, DRAW_TYPE draw_type) {
7574ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawDispatchType(dev_data, cb_state, bind_point, cmd_type);
7575c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis    updateResourceTrackingOnDraw(cb_state);
7576ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    cb_state->drawCount[draw_type]++;
7577ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis}
7578ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis
7579ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDraw(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed, VkPipelineBindPoint bind_point,
7580ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                   GLOBAL_CB_NODE **cb_state, const char *caller) {
7581baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    return ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAW, cb_state, caller, VK_QUEUE_GRAPHICS_BIT,
7582baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                               VALIDATION_ERROR_01364, VALIDATION_ERROR_01365, VALIDATION_ERROR_02203);
7583ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis}
7584ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis
7585ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDraw(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point) {
7586ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawType(dev_data, cb_state, bind_point, CMD_DRAW, DRAW);
7587c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis}
7588c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis
758989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount,
759089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                   uint32_t firstVertex, uint32_t firstInstance) {
759156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
759258b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
7593b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7594ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    bool skip = PreCallValidateCmdDraw(dev_data, commandBuffer, false, VK_PIPELINE_BIND_POINT_GRAPHICS, &cb_state, "vkCmdDraw()");
7595b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
759658b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    if (!skip) {
75974a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDraw(commandBuffer, vertexCount, instanceCount, firstVertex, firstInstance);
7598c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis        lock.lock();
7599ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDraw(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS);
7600c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis        lock.unlock();
7601c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis    }
76025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
76035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7604ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDrawIndexed(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed,
7605ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                          VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state, const char *caller) {
7606baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    return ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAWINDEXED, cb_state, caller, VK_QUEUE_GRAPHICS_BIT,
7607baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                               VALIDATION_ERROR_01371, VALIDATION_ERROR_01372, VALIDATION_ERROR_02216);
7608ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis}
7609ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis
7610ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDrawIndexed(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point) {
7611ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawType(dev_data, cb_state, bind_point, CMD_DRAWINDEXED, DRAW_INDEXED);
7612ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis}
7613ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis
7614bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount,
7615bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                          uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance) {
761656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7617ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
7618b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7619ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    bool skip = PreCallValidateCmdDrawIndexed(dev_data, commandBuffer, true, VK_PIPELINE_BIND_POINT_GRAPHICS, &cb_state,
7620ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                              "vkCmdDrawIndexed()");
7621b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7622ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    if (!skip) {
76234a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDrawIndexed(commandBuffer, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
7624ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis        lock.lock();
7625ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDrawIndexed(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS);
7626ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis        lock.unlock();
7627ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    }
76285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
76295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7630ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDrawIndirect(layer_data *dev_data, VkCommandBuffer cmd_buffer, VkBuffer buffer, bool indexed,
7631ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                           VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state, BUFFER_STATE **buffer_state,
7632ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                           const char *caller) {
76334f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes    bool skip = ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAWINDIRECT, cb_state, caller,
7634baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                    VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_01380, VALIDATION_ERROR_01381, VALIDATION_ERROR_02234);
76359a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *buffer_state = GetBufferState(dev_data, buffer);
763635ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis    skip |= ValidateMemoryIsBoundToBuffer(dev_data, *buffer_state, caller, VALIDATION_ERROR_02544);
763713c4316d0072cbc5bf3cd729abef4d114f3c96edMark Lobodzinski    // TODO: If the drawIndirectFirstInstance feature is not enabled, all the firstInstance members of the
763813c4316d0072cbc5bf3cd729abef4d114f3c96edMark Lobodzinski    // VkDrawIndirectCommand structures accessed by this command must be 0, which will require access to the contents of 'buffer'.
7639d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    return skip;
7640d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis}
7641d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis
7642ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDrawIndirect(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
7643ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                          BUFFER_STATE *buffer_state) {
7644ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawType(dev_data, cb_state, bind_point, CMD_DRAWINDIRECT, DRAW_INDIRECT);
7645d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    AddCommandBufferBindingBuffer(dev_data, cb_state, buffer_state);
7646d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis}
7647d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis
7648bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count,
7649bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           uint32_t stride) {
765056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7651d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
7652d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    BUFFER_STATE *buffer_state = nullptr;
7653b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7654872a2f0ca3ffdeddfa7483e777191fa64b853892Tony Barbour    bool skip = PreCallValidateCmdDrawIndirect(dev_data, commandBuffer, buffer, false, VK_PIPELINE_BIND_POINT_GRAPHICS, &cb_state,
7655ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                               &buffer_state, "vkCmdDrawIndirect()");
7656b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7657d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    if (!skip) {
76584a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDrawIndirect(commandBuffer, buffer, offset, count, stride);
7659d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis        lock.lock();
7660ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDrawIndirect(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, buffer_state);
7661d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis        lock.unlock();
7662d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    }
76635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
76645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7665ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDrawIndexedIndirect(layer_data *dev_data, VkCommandBuffer cmd_buffer, VkBuffer buffer, bool indexed,
7666ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                  VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state,
7667ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                  BUFFER_STATE **buffer_state, const char *caller) {
7668ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    bool skip = ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAWINDEXEDINDIRECT, cb_state, caller,
7669baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                    VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_01392, VALIDATION_ERROR_01393, VALIDATION_ERROR_02272);
76709a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *buffer_state = GetBufferState(dev_data, buffer);
767135ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis    skip |= ValidateMemoryIsBoundToBuffer(dev_data, *buffer_state, caller, VALIDATION_ERROR_02545);
767213c4316d0072cbc5bf3cd729abef4d114f3c96edMark Lobodzinski    // TODO: If the drawIndirectFirstInstance feature is not enabled, all the firstInstance members of the
767313c4316d0072cbc5bf3cd729abef4d114f3c96edMark Lobodzinski    // VkDrawIndexedIndirectCommand structures accessed by this command must be 0, which will require access to the contents of
767413c4316d0072cbc5bf3cd729abef4d114f3c96edMark Lobodzinski    // 'buffer'.
76750c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    return skip;
76760c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis}
76770c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis
7678ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDrawIndexedIndirect(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
7679ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                 BUFFER_STATE *buffer_state) {
7680ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawType(dev_data, cb_state, bind_point, CMD_DRAWINDEXEDINDIRECT, DRAW_INDEXED_INDIRECT);
76810c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    AddCommandBufferBindingBuffer(dev_data, cb_state, buffer_state);
76820c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis}
76830c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis
7684bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
7685bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                  uint32_t count, uint32_t stride) {
768656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
76870c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
76880c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    BUFFER_STATE *buffer_state = nullptr;
7689b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
76900c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    bool skip = PreCallValidateCmdDrawIndexedIndirect(dev_data, commandBuffer, buffer, true, VK_PIPELINE_BIND_POINT_GRAPHICS,
7691ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                      &cb_state, &buffer_state, "vkCmdDrawIndexedIndirect()");
7692b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
76930c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    if (!skip) {
76944a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDrawIndexedIndirect(commandBuffer, buffer, offset, count, stride);
76950c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis        lock.lock();
7696ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDrawIndexedIndirect(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, buffer_state);
76970c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis        lock.unlock();
76980c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    }
76995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
77005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7701ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDispatch(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed,
7702ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                       VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state, const char *caller) {
7703baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    return ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DISPATCH, cb_state, caller, VK_QUEUE_COMPUTE_BIT,
7704baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                               VALIDATION_ERROR_01561, VALIDATION_ERROR_01562, VALIDATION_ERROR_UNDEFINED);
770525d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis}
770625d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis
7707ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDispatch(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point) {
7708ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawDispatchType(dev_data, cb_state, bind_point, CMD_DISPATCH);
770925d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis}
771025d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis
771189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z) {
771256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
771325d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
7714b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7715ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    bool skip =
7716ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PreCallValidateCmdDispatch(dev_data, commandBuffer, false, VK_PIPELINE_BIND_POINT_COMPUTE, &cb_state, "vkCmdDispatch()");
7717b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
771825d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis    if (!skip) {
77194a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDispatch(commandBuffer, x, y, z);
772025d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis        lock.lock();
7721ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDispatch(dev_data, cb_state, VK_PIPELINE_BIND_POINT_COMPUTE);
772225d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis        lock.unlock();
772325d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis    }
77245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
77255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7726ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDispatchIndirect(layer_data *dev_data, VkCommandBuffer cmd_buffer, VkBuffer buffer, bool indexed,
7727ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                               VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state,
7728ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                               BUFFER_STATE **buffer_state, const char *caller) {
7729baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    bool skip =
7730baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DISPATCHINDIRECT, cb_state, caller, VK_QUEUE_COMPUTE_BIT,
7731baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                            VALIDATION_ERROR_01568, VALIDATION_ERROR_01569, VALIDATION_ERROR_UNDEFINED);
77329a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *buffer_state = GetBufferState(dev_data, buffer);
773335ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis    skip |= ValidateMemoryIsBoundToBuffer(dev_data, *buffer_state, caller, VALIDATION_ERROR_02547);
773479c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    return skip;
773579c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis}
773679c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis
7737ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDispatchIndirect(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
7738ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                              BUFFER_STATE *buffer_state) {
7739ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawDispatchType(dev_data, cb_state, bind_point, CMD_DISPATCHINDIRECT);
774079c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    AddCommandBufferBindingBuffer(dev_data, cb_state, buffer_state);
774179c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis}
774279c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis
7743bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset) {
774456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
774579c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
774679c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    BUFFER_STATE *buffer_state = nullptr;
7747b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
77487433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis    bool skip = PreCallValidateCmdDispatchIndirect(dev_data, commandBuffer, buffer, false, VK_PIPELINE_BIND_POINT_COMPUTE,
7749ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                   &cb_state, &buffer_state, "vkCmdDispatchIndirect()");
7750b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
775179c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    if (!skip) {
77524a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDispatchIndirect(commandBuffer, buffer, offset);
775379c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis        lock.lock();
7754ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDispatchIndirect(dev_data, cb_state, VK_PIPELINE_BIND_POINT_COMPUTE, buffer_state);
775579c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis        lock.unlock();
775679c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    }
77575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
77585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
775989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
776089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                         uint32_t regionCount, const VkBufferCopy *pRegions) {
7761c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7762b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7763ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
7764c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski    auto cb_node = GetCBNode(device_data, commandBuffer);
7765c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski    auto src_buffer_state = GetBufferState(device_data, srcBuffer);
7766c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski    auto dst_buffer_state = GetBufferState(device_data, dstBuffer);
7767593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
7768c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski    if (cb_node && src_buffer_state && dst_buffer_state) {
7769c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski        bool skip = PreCallValidateCmdCopyBuffer(device_data, cb_node, src_buffer_state, dst_buffer_state);
7770c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski        if (!skip) {
7771c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski            PreCallRecordCmdCopyBuffer(device_data, cb_node, src_buffer_state, dst_buffer_state);
7772c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski            lock.unlock();
7773c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski            device_data->dispatch_table.CmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, regionCount, pRegions);
7774c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski        }
7775ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
7776c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski        lock.unlock();
7777ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
77785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
77795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
77805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7781bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
7782bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
7783bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        const VkImageCopy *pRegions) {
77846a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    bool skip = false;
77856a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7786b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7787249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis
77886a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    auto cb_node = GetCBNode(device_data, commandBuffer);
77896a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    auto src_image_state = GetImageState(device_data, srcImage);
77906a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    auto dst_image_state = GetImageState(device_data, dstImage);
77911facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (cb_node && src_image_state && dst_image_state) {
77926a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski        skip = PreCallValidateCmdCopyImage(device_data, cb_node, src_image_state, dst_image_state, regionCount, pRegions,
77936a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski                                           srcImageLayout, dstImageLayout);
77946a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski        if (!skip) {
7795a07ae8bd5f566eb9b073498dd4280efdb0b838b9Tobin Ehlis            PreCallRecordCmdCopyImage(device_data, cb_node, src_image_state, dst_image_state, regionCount, pRegions, srcImageLayout,
7796a07ae8bd5f566eb9b073498dd4280efdb0b838b9Tobin Ehlis                                      dstImageLayout);
77976a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski            lock.unlock();
77986a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski            device_data->dispatch_table.CmdCopyImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
77996a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski                                                     pRegions);
78005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7801249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis    } else {
78026a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski        lock.unlock();
7803249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis        assert(0);
78045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
78055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
78065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7807eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski// Validate that an image's sampleCount matches the requirement for a specific API call
780860568995aca225f81acda8ce40cfabbea2c19397Mark Lobodzinskibool ValidateImageSampleCount(layer_data *dev_data, IMAGE_STATE *image_state, VkSampleCountFlagBits sample_count,
780960568995aca225f81acda8ce40cfabbea2c19397Mark Lobodzinski                              const char *location, UNIQUE_VALIDATION_ERROR_CODE msgCode) {
7810eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski    bool skip = false;
78111facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (image_state->createInfo.samples != sample_count) {
781255eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen        skip =
781355eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
781455eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                    reinterpret_cast<uint64_t &>(image_state->image), 0, msgCode, "DS",
781555eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                    "%s for image 0x%" PRIxLEAST64 " was created with a sample count of %s but must be %s. %s", location,
781655eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                    reinterpret_cast<uint64_t &>(image_state->image), string_VkSampleCountFlagBits(image_state->createInfo.samples),
781755eb01e5950bcb079893cbeee2b487d7e16a79e2Mike Weiblen                    string_VkSampleCountFlagBits(sample_count), validation_error_map[msgCode]);
7818eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski    }
7819eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski    return skip;
7820eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski}
7821eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski
7822bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
7823bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
7824bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        const VkImageBlit *pRegions, VkFilter filter) {
782556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7826b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7827593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
78289a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
78299a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto src_image_state = GetImageState(dev_data, srcImage);
78309a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto dst_image_state = GetImageState(dev_data, dstImage);
78310dc51740dbd7b9f0ba7c071e0bf96f63d6d48c85Mark Lobodzinski
7832055112ec99304db71d55b69a60e1da14e8af8f60Mark Lobodzinski    bool skip = PreCallValidateCmdBlitImage(dev_data, cb_node, src_image_state, dst_image_state, regionCount, pRegions, filter);
78330dc51740dbd7b9f0ba7c071e0bf96f63d6d48c85Mark Lobodzinski
7834dca02371c9531e7a9a2a51decae1db4d297862c4Mark Lobodzinski    if (!skip) {
7835eebd811afd800663f15fda8fc71bc203a03fe294Mark Lobodzinski        PreCallRecordCmdBlitImage(dev_data, cb_node, src_image_state, dst_image_state);
7836eebd811afd800663f15fda8fc71bc203a03fe294Mark Lobodzinski        lock.unlock();
78374a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdBlitImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
78384a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                              pRegions, filter);
78390dc51740dbd7b9f0ba7c071e0bf96f63d6d48c85Mark Lobodzinski    }
78405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
78415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7842bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage,
7843bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                VkImageLayout dstImageLayout, uint32_t regionCount,
7844bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkBufferImageCopy *pRegions) {
7845940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7846b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7847940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    bool skip = false;
7848940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto cb_node = GetCBNode(device_data, commandBuffer);
7849940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto src_buffer_state = GetBufferState(device_data, srcBuffer);
7850940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto dst_image_state = GetImageState(device_data, dstImage);
7851940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    if (cb_node && src_buffer_state && dst_image_state) {
7852940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski        skip = PreCallValidateCmdCopyBufferToImage(device_data, dstImageLayout, cb_node, src_buffer_state, dst_image_state,
785371c68ce753146a69508694cfc5fc2dcfa08c692eMark Lobodzinski                                                        regionCount, pRegions, "vkCmdCopyBufferToImage()");
7854ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
7855d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski        lock.unlock();
7856ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
7857e4d82c37d6c861b388dbc80297c18d6255858cb4Dave Houlton        // TODO: report VU01244 here, or put in object tracker?
78585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7859940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    if (!skip) {
7860a07ae8bd5f566eb9b073498dd4280efdb0b838b9Tobin Ehlis        PreCallRecordCmdCopyBufferToImage(device_data, cb_node, src_buffer_state, dst_image_state, regionCount, pRegions,
7861a07ae8bd5f566eb9b073498dd4280efdb0b838b9Tobin Ehlis                                          dstImageLayout);
7862d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski        lock.unlock();
7863940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski        device_data->dispatch_table.CmdCopyBufferToImage(commandBuffer, srcBuffer, dstImage, dstImageLayout, regionCount, pRegions);
7864d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski    }
78655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
78665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7867bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
7868bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy *pRegions) {
7869940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    bool skip = false;
7870940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7871b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7872593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
7873940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto cb_node = GetCBNode(device_data, commandBuffer);
7874940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto src_image_state = GetImageState(device_data, srcImage);
7875940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto dst_buffer_state = GetBufferState(device_data, dstBuffer);
7876940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    if (cb_node && src_image_state && dst_buffer_state) {
7877940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski        skip = PreCallValidateCmdCopyImageToBuffer(device_data, srcImageLayout, cb_node, src_image_state, dst_buffer_state,
787871c68ce753146a69508694cfc5fc2dcfa08c692eMark Lobodzinski                                                        regionCount, pRegions, "vkCmdCopyImageToBuffer()");
7879ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
7880d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski        lock.unlock();
7881ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
7882e4d82c37d6c861b388dbc80297c18d6255858cb4Dave Houlton        // TODO: report VU01262 here, or put in object tracker?
78835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7884940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    if (!skip) {
7885a07ae8bd5f566eb9b073498dd4280efdb0b838b9Tobin Ehlis        PreCallRecordCmdCopyImageToBuffer(device_data, cb_node, src_image_state, dst_buffer_state, regionCount, pRegions,
7886a07ae8bd5f566eb9b073498dd4280efdb0b838b9Tobin Ehlis                                          srcImageLayout);
7887d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski        lock.unlock();
7888940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski        device_data->dispatch_table.CmdCopyImageToBuffer(commandBuffer, srcImage, srcImageLayout, dstBuffer, regionCount, pRegions);
7889d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski    }
78905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
78915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7892bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
7893bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           VkDeviceSize dataSize, const uint32_t *pData) {
789483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
789556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7896b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7897593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
78989a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
78999a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto dst_buff_state = GetBufferState(dev_data, dstBuffer);
79005cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (cb_node && dst_buff_state) {
790135ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis        skip_call |= ValidateMemoryIsBoundToBuffer(dev_data, dst_buff_state, "vkCmdUpdateBuffer()", VALIDATION_ERROR_02530);
7902ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Update bindings between buffer and cmd buffer
79035cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        AddCommandBufferBindingBuffer(dev_data, cb_node, dst_buff_state);
7904ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Validate that DST buffer has correct usage flags set
79055cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        skip_call |= ValidateBufferUsageFlags(dev_data, dst_buff_state, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true,
79061b8a6bd9260c52ca6c6cfe1e34f142f93e1e2cc6Jeremy Hayes                                              VALIDATION_ERROR_01146, "vkCmdUpdateBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
7907e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
79085cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            SetBufferMemoryValid(dev_data, dst_buff_state, true);
7909e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
79105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        };
79119f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
7912593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
7913baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip_call |=
7914baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt            ValidateCmdQueueFlags(dev_data, cb_node, "vkCmdUpdateBuffer()",
7915baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                  VK_QUEUE_TRANSFER_BIT | VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, VALIDATION_ERROR_01154);
791629f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, cb_node, CMD_UPDATEBUFFER, "vkCmdUpdateBuffer()");
79171ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(cb_node, CMD_UPDATEBUFFER);
7918ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen        skip_call |= insideRenderPass(dev_data, cb_node, "vkCmdUpdateBuffer()", VALIDATION_ERROR_01155);
7919ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
7920ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
79215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7922b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7923cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdUpdateBuffer(commandBuffer, dstBuffer, dstOffset, dataSize, pData);
79245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
79255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7926bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
7927bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         VkDeviceSize size, uint32_t data) {
792823bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7929b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
793023bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski    auto cb_node = GetCBNode(device_data, commandBuffer);
793123bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski    auto buffer_state = GetBufferState(device_data, dstBuffer);
7932593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
793323bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski    if (cb_node && buffer_state) {
793423bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski        bool skip = PreCallValidateCmdFillBuffer(device_data, cb_node, buffer_state);
793523bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski        if (!skip) {
793623bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski            PreCallRecordCmdFillBuffer(device_data, cb_node, buffer_state);
793723bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski            lock.unlock();
793823bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski            device_data->dispatch_table.CmdFillBuffer(commandBuffer, dstBuffer, dstOffset, size, data);
793923bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski        }
7940ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
794123bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski        lock.unlock();
7942ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
79435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
79445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
79455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
79464028af23e688ab5730f48ab2244dd042e2eefaedMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount,
79474028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski                                               const VkClearAttachment *pAttachments, uint32_t rectCount,
79484028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski                                               const VkClearRect *pRects) {
79494028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski    bool skip = false;
795056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
79514028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski    {
79524028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski        std::lock_guard<std::mutex> lock(global_lock);
79534028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski        skip = PreCallValidateCmdClearAttachments(dev_data, commandBuffer, attachmentCount, pAttachments, rectCount, pRects);
79544028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski    }
7955cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdClearAttachments(commandBuffer, attachmentCount, pAttachments, rectCount, pRects);
79565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
79575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
79580482c55760707900fcd072f6895c121bcf055f6eMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
79590482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski                                              const VkClearColorValue *pColor, uint32_t rangeCount,
79600482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski                                              const VkImageSubresourceRange *pRanges) {
796156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7962b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
79630482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski
79640482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    bool skip = PreCallValidateCmdClearColorImage(dev_data, commandBuffer, image, imageLayout, rangeCount, pRanges);
79650482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    if (!skip) {
79660482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        PreCallRecordCmdClearImage(dev_data, commandBuffer, image, imageLayout, rangeCount, pRanges, CMD_CLEARCOLORIMAGE);
79670482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        lock.unlock();
79680482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        dev_data->dispatch_table.CmdClearColorImage(commandBuffer, image, imageLayout, pColor, rangeCount, pRanges);
79690482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    }
79700482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski}
79710482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski
79720482c55760707900fcd072f6895c121bcf055f6eMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
79730482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski                                                     const VkClearDepthStencilValue *pDepthStencil, uint32_t rangeCount,
79740482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski                                                     const VkImageSubresourceRange *pRanges) {
797556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
79760482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    std::unique_lock<std::mutex> lock(global_lock);
79770482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski
79780482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    bool skip = PreCallValidateCmdClearDepthStencilImage(dev_data, commandBuffer, image, imageLayout, rangeCount, pRanges);
79790482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    if (!skip) {
79800482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        PreCallRecordCmdClearImage(dev_data, commandBuffer, image, imageLayout, rangeCount, pRanges, CMD_CLEARDEPTHSTENCILIMAGE);
79810482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        lock.unlock();
79820482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        dev_data->dispatch_table.CmdClearDepthStencilImage(commandBuffer, image, imageLayout, pDepthStencil, rangeCount, pRanges);
79837f8aa8f5abceedbb599ef69af1dfbb38c0df2660Slawomir Cygan    }
79845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
79855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7986bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
7987bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
7988bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           const VkImageResolve *pRegions) {
798956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7990b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7991593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
79929a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
79939a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto src_image_state = GetImageState(dev_data, srcImage);
79949a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto dst_image_state = GetImageState(dev_data, dstImage);
799509fe5ac5edaec7f0dbcc9fd696e68194569aea89Mark Lobodzinski
799625f7873c9ce3ed39d18bba8750d7538905e150dfMark Lobodzinski    bool skip = PreCallValidateCmdResolveImage(dev_data, cb_node, src_image_state, dst_image_state, regionCount, pRegions);
799709fe5ac5edaec7f0dbcc9fd696e68194569aea89Mark Lobodzinski
799809fe5ac5edaec7f0dbcc9fd696e68194569aea89Mark Lobodzinski    if (!skip) {
79996c0400e625554ce7fddb833eeace0de19cfcc965Mark Lobodzinski        PreCallRecordCmdResolveImage(dev_data, cb_node, src_image_state, dst_image_state);
80006c0400e625554ce7fddb833eeace0de19cfcc965Mark Lobodzinski        lock.unlock();
80014a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdResolveImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
80024a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                 pRegions);
800309fe5ac5edaec7f0dbcc9fd696e68194569aea89Mark Lobodzinski    }
80045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
80055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8006a8d1e377bdeaf61a3209cb997502da4356a185bbMike WeiblenVKAPI_ATTR void VKAPI_CALL GetImageSubresourceLayout(VkDevice device, VkImage image, const VkImageSubresource *pSubresource,
8007a8d1e377bdeaf61a3209cb997502da4356a185bbMike Weiblen                                                     VkSubresourceLayout *pLayout) {
8008a8d1e377bdeaf61a3209cb997502da4356a185bbMike Weiblen    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
8009a8d1e377bdeaf61a3209cb997502da4356a185bbMike Weiblen
8010a8d1e377bdeaf61a3209cb997502da4356a185bbMike Weiblen    bool skip = PreCallValidateGetImageSubresourceLayout(device_data, image, pSubresource);
8011a8d1e377bdeaf61a3209cb997502da4356a185bbMike Weiblen    if (!skip) {
8012b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski        device_data->dispatch_table.GetImageSubresourceLayout(device, image, pSubresource, pLayout);
8013b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski    }
8014b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski}
8015b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski
8016b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentinebool setEventStageMask(VkQueue queue, VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
801756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
80189a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
8019b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    if (pCB) {
8020b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        pCB->eventToStageMap[event] = stageMask;
8021b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
8022b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    auto queue_data = dev_data->queueMap.find(queue);
8023b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    if (queue_data != dev_data->queueMap.end()) {
8024b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        queue_data->second.eventToStageMap[event] = stageMask;
8025b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
8026b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    return false;
8027b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine}
8028b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine
8029bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
803083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
803156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8032b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
80339a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
80345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
8035baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip_call |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetEvent()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
8036baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                           VALIDATION_ERROR_00237);
803729f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_SETEVENT, "vkCmdSetEvent()");
80381ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETEVENT);
8039ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen        skip_call |= insideRenderPass(dev_data, pCB, "vkCmdSetEvent()", VALIDATION_ERROR_00238);
8040208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip_call |=
8041208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis            ValidateStageMaskGsTsEnables(dev_data, stageMask, "vkCmdSetEvent()", VALIDATION_ERROR_00230, VALIDATION_ERROR_00231);
80429a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto event_state = GetEventNode(dev_data, event);
80434710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        if (event_state) {
80444710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis            addCommandBufferBinding(&event_state->cb_bindings,
8045ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis                                    {reinterpret_cast<uint64_t &>(event), VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT}, pCB);
80464710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis            event_state->cb_bindings.insert(pCB);
8047ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis        }
80485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->events.push_back(event);
8049c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine        if (!pCB->waitedEvents.count(event)) {
8050c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine            pCB->writeEventsBeforeWait.push_back(event);
8051c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine        }
8052b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        std::function<bool(VkQueue)> eventUpdate =
8053b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            std::bind(setEventStageMask, std::placeholders::_1, commandBuffer, event, stageMask);
8054b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        pCB->eventUpdates.push_back(eventUpdate);
80555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8056b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8057cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdSetEvent(commandBuffer, event, stageMask);
80585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
80595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8060bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdResetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
806183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
806256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8063b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
80649a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
80655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
8066baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip_call |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdResetEvent()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
8067baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                           VALIDATION_ERROR_00248);
806829f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_RESETEVENT, "vkCmdResetEvent()");
80691ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_RESETEVENT);
8070ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen        skip_call |= insideRenderPass(dev_data, pCB, "vkCmdResetEvent()", VALIDATION_ERROR_00249);
8071208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip_call |=
8072208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis            ValidateStageMaskGsTsEnables(dev_data, stageMask, "vkCmdResetEvent()", VALIDATION_ERROR_00240, VALIDATION_ERROR_00241);
80739a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto event_state = GetEventNode(dev_data, event);
80744710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        if (event_state) {
80754710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis            addCommandBufferBinding(&event_state->cb_bindings,
8076ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis                                    {reinterpret_cast<uint64_t &>(event), VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT}, pCB);
80774710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis            event_state->cb_bindings.insert(pCB);
8078ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis        }
80795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->events.push_back(event);
8080c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine        if (!pCB->waitedEvents.count(event)) {
8081c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine            pCB->writeEventsBeforeWait.push_back(event);
8082c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine        }
8083208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        // TODO : Add check for VALIDATION_ERROR_00226
8084b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        std::function<bool(VkQueue)> eventUpdate =
8085b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            std::bind(setEventStageMask, std::placeholders::_1, commandBuffer, event, VkPipelineStageFlags(0));
8086b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        pCB->eventUpdates.push_back(eventUpdate);
80875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8088b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8089cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdResetEvent(commandBuffer, event, stageMask);
80905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
80915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8092e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool ValidateBarriers(const char *funcName, VkCommandBuffer cmdBuffer, uint32_t memBarrierCount,
8093e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                             const VkMemoryBarrier *pMemBarriers, uint32_t bufferBarrierCount,
8094e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                             const VkBufferMemoryBarrier *pBufferMemBarriers, uint32_t imageMemBarrierCount,
8095e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                             const VkImageMemoryBarrier *pImageMemBarriers) {
8096a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis    bool skip = false;
809756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(cmdBuffer), layer_data_map);
80989a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, cmdBuffer);
80995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB->activeRenderPass && memBarrierCount) {
8100ee691f5c5fa87aac3750454d2bca2cb582e4e817Chris Forbes        if (!pCB->activeRenderPass->hasSelfDependency[pCB->activeSubpass]) {
8101df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
8102df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            reinterpret_cast<uint64_t>(cmdBuffer), __LINE__, DRAWSTATE_INVALID_BARRIER, "DS",
8103cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s: Barriers cannot be set during subpass %d "
8104cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "with no self dependency specified.",
8105a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            funcName, pCB->activeSubpass);
81065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
81075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
81085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < imageMemBarrierCount; ++i) {
81095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto mem_barrier = &pImageMemBarriers[i];
81109a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto image_data = GetImageState(dev_data, mem_barrier->image);
81116d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis        if (image_data) {
81125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t src_q_f_index = mem_barrier->srcQueueFamilyIndex;
81135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t dst_q_f_index = mem_barrier->dstQueueFamilyIndex;
81146d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            if (image_data->createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) {
81155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // srcQueueFamilyIndex and dstQueueFamilyIndex must both
81165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // be VK_QUEUE_FAMILY_IGNORED
81175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if ((src_q_f_index != VK_QUEUE_FAMILY_IGNORED) || (dst_q_f_index != VK_QUEUE_FAMILY_IGNORED)) {
8118df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
8119df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t>(cmdBuffer), __LINE__,
8120df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    DRAWSTATE_INVALID_QUEUE_INDEX, "DS",
8121df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    "%s: Image Barrier for image 0x%" PRIx64
8122df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    " was created with sharingMode of "
8123df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    "VK_SHARING_MODE_CONCURRENT. Src and dst "
8124df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    "queueFamilyIndices must be VK_QUEUE_FAMILY_IGNORED.",
8125df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    funcName, reinterpret_cast<const uint64_t &>(mem_barrier->image));
81265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
81275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else {
81285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // Sharing mode is VK_SHARING_MODE_EXCLUSIVE. srcQueueFamilyIndex and
81295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // dstQueueFamilyIndex must either both be VK_QUEUE_FAMILY_IGNORED,
81305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // or both be a valid queue family
81315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (((src_q_f_index == VK_QUEUE_FAMILY_IGNORED) || (dst_q_f_index == VK_QUEUE_FAMILY_IGNORED)) &&
81325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    (src_q_f_index != dst_q_f_index)) {
8133df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
8134df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t>(cmdBuffer), __LINE__,
8135df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    DRAWSTATE_INVALID_QUEUE_INDEX, "DS",
8136df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    "%s: Image 0x%" PRIx64
8137df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    " was created with sharingMode "
8138df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    "of VK_SHARING_MODE_EXCLUSIVE. If one of src- or "
8139df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    "dstQueueFamilyIndex is VK_QUEUE_FAMILY_IGNORED, both "
8140df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    "must be.",
8141df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    funcName, reinterpret_cast<const uint64_t &>(mem_barrier->image));
81425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                } else if (((src_q_f_index != VK_QUEUE_FAMILY_IGNORED) && (dst_q_f_index != VK_QUEUE_FAMILY_IGNORED)) &&
8143b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis                           ((src_q_f_index >= dev_data->phys_dev_properties.queue_family_properties.size()) ||
8144b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis                            (dst_q_f_index >= dev_data->phys_dev_properties.queue_family_properties.size()))) {
8145df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
8146df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t>(cmdBuffer), __LINE__,
8147df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    DRAWSTATE_INVALID_QUEUE_INDEX, "DS",
8148cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    "%s: Image 0x%" PRIx64
8149cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    " was created with sharingMode "
8150a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                    "of VK_SHARING_MODE_EXCLUSIVE, but srcQueueFamilyIndex %d"
8151a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                    " or dstQueueFamilyIndex %d is greater than " PRINTF_SIZE_T_SPECIFIER
8152a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                    "queueFamilies crated for this device.",
8153a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                    funcName, reinterpret_cast<const uint64_t &>(mem_barrier->image), src_q_f_index, dst_q_f_index,
8154a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                                    dev_data->phys_dev_properties.queue_family_properties.size());
81555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
81565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
81575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
81585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
81595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (mem_barrier) {
8160d678ec4f57d80aa89c24562e9ffe941d8d69e455Tony Barbour            if (mem_barrier->oldLayout != mem_barrier->newLayout) {
8161a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                skip |=
8162d678ec4f57d80aa89c24562e9ffe941d8d69e455Tony Barbour                    ValidateMaskBitsFromLayouts(dev_data, cmdBuffer, mem_barrier->srcAccessMask, mem_barrier->oldLayout, "Source");
8163a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                skip |=
8164d678ec4f57d80aa89c24562e9ffe941d8d69e455Tony Barbour                    ValidateMaskBitsFromLayouts(dev_data, cmdBuffer, mem_barrier->dstAccessMask, mem_barrier->newLayout, "Dest");
8165d678ec4f57d80aa89c24562e9ffe941d8d69e455Tony Barbour            }
81665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (mem_barrier->newLayout == VK_IMAGE_LAYOUT_UNDEFINED || mem_barrier->newLayout == VK_IMAGE_LAYOUT_PREINITIALIZED) {
8167df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                skip |=
8168df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
8169df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            reinterpret_cast<uint64_t>(cmdBuffer), __LINE__, DRAWSTATE_INVALID_BARRIER, "DS",
8170df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "%s: Image Layout cannot be transitioned to UNDEFINED or "
8171df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "PREINITIALIZED.",
8172df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            funcName);
81735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
81741d5109d5e0dcc530b27e632e73e1be5e12a28dcdJamie Madill            VkFormat format = VK_FORMAT_UNDEFINED;
81751d5109d5e0dcc530b27e632e73e1be5e12a28dcdJamie Madill            uint32_t arrayLayers = 0, mipLevels = 0;
81765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            bool imageFound = false;
81776d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            if (image_data) {
81786d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis                format = image_data->createInfo.format;
81796d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis                arrayLayers = image_data->createInfo.arrayLayers;
81806d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis                mipLevels = image_data->createInfo.mipLevels;
81815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                imageFound = true;
81825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else if (dev_data->device_extensions.wsi_enabled) {
81839a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto imageswap_data = GetSwapchainFromImage(dev_data, mem_barrier->image);
8184170dc65b45f6bcdec47e02b3aa19435e55b32804Tobin Ehlis                if (imageswap_data) {
81859a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto swapchain_data = GetSwapchainNode(dev_data, imageswap_data);
8186b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis                    if (swapchain_data) {
8187b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis                        format = swapchain_data->createInfo.imageFormat;
8188b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis                        arrayLayers = swapchain_data->createInfo.imageArrayLayers;
81895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        mipLevels = 1;
81905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        imageFound = true;
81915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
81925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
81935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
81945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (imageFound) {
8195e08b485346524a30ddfe6526f7dcbbf78c776d10Mark Lobodzinski                skip |= ValidateImageSubrangeLevelLayerCounts(dev_data, mem_barrier->subresourceRange, funcName);
8196c37c65e9ff3a0abc86e706ee61d21e1dec882731Tobin Ehlis                auto aspect_mask = mem_barrier->subresourceRange.aspectMask;
8197a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                skip |= ValidateImageAspectMask(dev_data, image_data->image, format, aspect_mask, funcName);
819895b7894efd5e101e410da92fc697429aec3ffa7bMark Lobodzinski
819995b7894efd5e101e410da92fc697429aec3ffa7bMark Lobodzinski                uint32_t layer_count = ResolveRemainingLayers(&mem_barrier->subresourceRange, image_data->createInfo.arrayLayers);
820095b7894efd5e101e410da92fc697429aec3ffa7bMark Lobodzinski                if ((mem_barrier->subresourceRange.baseArrayLayer + layer_count) > arrayLayers) {
8201df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
820295b7894efd5e101e410da92fc697429aec3ffa7bMark Lobodzinski                                    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t>(cmdBuffer), __LINE__,
820395b7894efd5e101e410da92fc697429aec3ffa7bMark Lobodzinski                                    DRAWSTATE_INVALID_BARRIER, "DS",
820495b7894efd5e101e410da92fc697429aec3ffa7bMark Lobodzinski                                    "%s: Subresource must have the sum of the baseArrayLayer (%d) and layerCount (%d) be less "
8205cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    "than or equal to the total number of layers (%d).",
820695b7894efd5e101e410da92fc697429aec3ffa7bMark Lobodzinski                                    funcName, mem_barrier->subresourceRange.baseArrayLayer, layer_count, arrayLayers);
82075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
820895b7894efd5e101e410da92fc697429aec3ffa7bMark Lobodzinski
820995b7894efd5e101e410da92fc697429aec3ffa7bMark Lobodzinski                uint32_t level_count = ResolveRemainingLevels(&mem_barrier->subresourceRange, image_data->createInfo.mipLevels);
821095b7894efd5e101e410da92fc697429aec3ffa7bMark Lobodzinski                if ((mem_barrier->subresourceRange.baseMipLevel + level_count) > mipLevels) {
8211df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    skip |= log_msg(
8212df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
8213df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        reinterpret_cast<uint64_t>(cmdBuffer), __LINE__, DRAWSTATE_INVALID_BARRIER, "DS",
821495b7894efd5e101e410da92fc697429aec3ffa7bMark Lobodzinski                        "%s: Subresource must have the sum of the baseMipLevel (%d) and levelCount (%d) be less than or equal to "
8215df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        "the total number of levels (%d).",
821695b7894efd5e101e410da92fc697429aec3ffa7bMark Lobodzinski                        funcName, mem_barrier->subresourceRange.baseMipLevel, level_count, mipLevels);
82175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
82185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
82195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
82205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
82215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < bufferBarrierCount; ++i) {
82225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto mem_barrier = &pBufferMemBarriers[i];
82235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (pCB->activeRenderPass) {
8224df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
8225df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            reinterpret_cast<uint64_t>(cmdBuffer), __LINE__, DRAWSTATE_INVALID_BARRIER, "DS",
8226df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "%s: Buffer Barriers cannot be used during a render pass.", funcName);
82275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8228cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!mem_barrier) continue;
82295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
82305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Validate buffer barrier queue family indices
82315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if ((mem_barrier->srcQueueFamilyIndex != VK_QUEUE_FAMILY_IGNORED &&
8232b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis             mem_barrier->srcQueueFamilyIndex >= dev_data->phys_dev_properties.queue_family_properties.size()) ||
82335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            (mem_barrier->dstQueueFamilyIndex != VK_QUEUE_FAMILY_IGNORED &&
8234b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis             mem_barrier->dstQueueFamilyIndex >= dev_data->phys_dev_properties.queue_family_properties.size())) {
8235df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
8236df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            reinterpret_cast<uint64_t>(cmdBuffer), __LINE__, DRAWSTATE_INVALID_QUEUE_INDEX, "DS",
8237cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s: Buffer Barrier 0x%" PRIx64
8238cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            " has QueueFamilyIndex greater "
8239a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            "than the number of QueueFamilies (" PRINTF_SIZE_T_SPECIFIER ") for this device.",
8240a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            funcName, reinterpret_cast<const uint64_t &>(mem_barrier->buffer),
8241a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            dev_data->phys_dev_properties.queue_family_properties.size());
82425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
82435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
82449a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto buffer_state = GetBufferState(dev_data, mem_barrier->buffer);
82455cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        if (buffer_state) {
82465cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            auto buffer_size = buffer_state->requirements.size;
82475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (mem_barrier->offset >= buffer_size) {
8248a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                skip |= log_msg(
8249df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
8250df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    reinterpret_cast<uint64_t>(cmdBuffer), __LINE__, DRAWSTATE_INVALID_BARRIER, "DS",
8251df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    "%s: Buffer Barrier 0x%" PRIx64 " has offset 0x%" PRIx64 " which is not less than total size 0x%" PRIx64 ".",
825294c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis                    funcName, reinterpret_cast<const uint64_t &>(mem_barrier->buffer),
8253df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    reinterpret_cast<const uint64_t &>(mem_barrier->offset), reinterpret_cast<const uint64_t &>(buffer_size));
8254df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            } else if (mem_barrier->size != VK_WHOLE_SIZE && (mem_barrier->offset + mem_barrier->size > buffer_size)) {
8255df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                skip |=
8256df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
8257df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            reinterpret_cast<uint64_t>(cmdBuffer), __LINE__, DRAWSTATE_INVALID_BARRIER, "DS",
8258df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "%s: Buffer Barrier 0x%" PRIx64 " has offset 0x%" PRIx64 " and size 0x%" PRIx64
8259df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            " whose sum is greater than total size 0x%" PRIx64 ".",
8260df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            funcName, reinterpret_cast<const uint64_t &>(mem_barrier->buffer),
8261df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            reinterpret_cast<const uint64_t &>(mem_barrier->offset),
8262df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            reinterpret_cast<const uint64_t &>(mem_barrier->size), reinterpret_cast<const uint64_t &>(buffer_size));
82635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
82645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
82655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8266a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis    return skip;
82675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
82685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8269bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskibool validateEventStageMask(VkQueue queue, GLOBAL_CB_NODE *pCB, uint32_t eventCount, size_t firstEventIndex,
8270bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            VkPipelineStageFlags sourceStageMask) {
8271b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    bool skip_call = false;
8272b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    VkPipelineStageFlags stageMask = 0;
827356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
8274b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    for (uint32_t i = 0; i < eventCount; ++i) {
82752ab14387df9b890fe4b13494ea249dd03cf898d2Chris Forbes        auto event = pCB->events[firstEventIndex + i];
8276b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        auto queue_data = dev_data->queueMap.find(queue);
8277cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (queue_data == dev_data->queueMap.end()) return false;
82782ab14387df9b890fe4b13494ea249dd03cf898d2Chris Forbes        auto event_data = queue_data->second.eventToStageMap.find(event);
8279b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        if (event_data != queue_data->second.eventToStageMap.end()) {
8280b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            stageMask |= event_data->second;
8281b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        } else {
82829a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto global_event_data = GetEventNode(dev_data, event);
82839556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis            if (!global_event_data) {
8284b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT,
828527c3e0dda9e30d1d334728bbd373e8d7011257d4Chris Forbes                                     reinterpret_cast<const uint64_t &>(event), __LINE__, DRAWSTATE_INVALID_EVENT, "DS",
828627c3e0dda9e30d1d334728bbd373e8d7011257d4Chris Forbes                                     "Event 0x%" PRIx64 " cannot be waited on if it has never been set.",
82872ab14387df9b890fe4b13494ea249dd03cf898d2Chris Forbes                                     reinterpret_cast<const uint64_t &>(event));
8288b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            } else {
82899556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis                stageMask |= global_event_data->stageMask;
8290b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            }
8291b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        }
8292b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
8293c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    // TODO: Need to validate that host_bit is only set if set event is called
8294c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    // but set event can be called at any time.
8295c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    if (sourceStageMask != stageMask && sourceStageMask != (stageMask | VK_PIPELINE_STAGE_HOST_BIT)) {
8296df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
8297df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                             reinterpret_cast<uint64_t>(pCB->commandBuffer), __LINE__, VALIDATION_ERROR_00254, "DS",
8298cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "Submitting cmdbuffer with call to VkCmdWaitEvents "
8299cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "using srcStageMask 0x%X which must be the bitwise "
8300cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "OR of the stageMask parameters used in calls to "
8301cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "vkCmdSetEvent and VK_PIPELINE_STAGE_HOST_BIT if "
8302cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                             "used with vkSetEvent but instead is 0x%X. %s",
83039bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             sourceStageMask, stageMask, validation_error_map[VALIDATION_ERROR_00254]);
8304b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
8305b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    return skip_call;
8306b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine}
8307b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine
830807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski// Note that we only check bits that HAVE required queueflags -- don't care entries are skipped
830907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinskistatic std::unordered_map<VkPipelineStageFlags, VkQueueFlags> supported_pipeline_stages_table = {
831007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT},
831107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT},
831207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_QUEUE_GRAPHICS_BIT},
831307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
831407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
831507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
831607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
831707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
831807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, VK_QUEUE_GRAPHICS_BIT},
831907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_QUEUE_GRAPHICS_BIT},
832007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_QUEUE_GRAPHICS_BIT},
832107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_QUEUE_COMPUTE_BIT},
832207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_TRANSFER_BIT, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT},
832307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_QUEUE_GRAPHICS_BIT}};
832407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
832507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinskistatic const VkPipelineStageFlags stage_flag_bit_array[] = {VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX,
832607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,
832707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
832807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
832907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT,
833007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT,
833107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT,
833207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
833307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
833407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
833507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
833607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
833707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_TRANSFER_BIT,
833807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT};
833907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
834007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinskibool CheckStageMaskQueueCompatibility(layer_data *dev_data, VkCommandBuffer command_buffer, VkPipelineStageFlags stage_mask,
834107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                      VkQueueFlags queue_flags, const char *function, const char *src_or_dest,
834207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                      UNIQUE_VALIDATION_ERROR_CODE error_code) {
834307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    bool skip = false;
834407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    // Lookup each bit in the stagemask and check for overlap between its table bits and queue_flags
834507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    for (const auto &item : stage_flag_bit_array) {
834607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        if (stage_mask & item) {
834707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski            if ((supported_pipeline_stages_table[item] & queue_flags) == 0) {
834807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                skip |=
834907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
835007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            reinterpret_cast<uint64_t &>(command_buffer), __LINE__, error_code, "DL",
835107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            "%s(): %s flag %s is not compatible with the queue family properties of this "
835207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            "command buffer. %s",
835307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            function, src_or_dest, string_VkPipelineStageFlagBits(static_cast<VkPipelineStageFlagBits>(item)),
835407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            validation_error_map[error_code]);
835507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski            }
835607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        }
835707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    }
835807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    return skip;
835907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski}
836007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
836107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinskibool ValidateStageMasksAgainstQueueCapabilities(layer_data *dev_data, GLOBAL_CB_NODE *cb_state,
836207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                VkPipelineStageFlags source_stage_mask, VkPipelineStageFlags dest_stage_mask,
836307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                const char *function, UNIQUE_VALIDATION_ERROR_CODE error_code) {
836407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    bool skip = false;
836507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    uint32_t queue_family_index = dev_data->commandPoolMap[cb_state->createInfo.commandPool].queueFamilyIndex;
836656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(dev_data->physical_device), instance_layer_data_map);
83679a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, dev_data->physical_device);
836807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
836907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    // Any pipeline stage included in srcStageMask or dstStageMask must be supported by the capabilities of the queue family
837007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    // specified by the queueFamilyIndex member of the VkCommandPoolCreateInfo structure that was used to create the VkCommandPool
837107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    // that commandBuffer was allocated from, as specified in the table of supported pipeline stages.
837207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
837307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    if (queue_family_index < physical_device_state->queue_family_properties.size()) {
837407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        VkQueueFlags specified_queue_flags = physical_device_state->queue_family_properties[queue_family_index].queueFlags;
837507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
837607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        if ((source_stage_mask & VK_PIPELINE_STAGE_ALL_COMMANDS_BIT) == 0) {
837707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski            skip |= CheckStageMaskQueueCompatibility(dev_data, cb_state->commandBuffer, source_stage_mask, specified_queue_flags,
837807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                     function, "srcStageMask", error_code);
837907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        }
838007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        if ((dest_stage_mask & VK_PIPELINE_STAGE_ALL_COMMANDS_BIT) == 0) {
838107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski            skip |= CheckStageMaskQueueCompatibility(dev_data, cb_state->commandBuffer, dest_stage_mask, specified_queue_flags,
838207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                     function, "dstStageMask", error_code);
838307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        }
838407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    }
838507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    return skip;
838607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski}
838707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
8388d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents,
8389d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                         VkPipelineStageFlags sourceStageMask, VkPipelineStageFlags dstStageMask,
8390d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                         uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
8391d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                         uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
8392d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                         uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
8393d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    bool skip = false;
839456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8395b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
83969a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
8397d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    if (cb_state) {
8398d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        skip |= ValidateStageMasksAgainstQueueCapabilities(dev_data, cb_state, sourceStageMask, dstStageMask, "vkCmdWaitEvents",
8399d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                                           VALIDATION_ERROR_02510);
8400208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip |= ValidateStageMaskGsTsEnables(dev_data, sourceStageMask, "vkCmdWaitEvents()", VALIDATION_ERROR_02067,
8401208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                                             VALIDATION_ERROR_02069);
8402208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip |= ValidateStageMaskGsTsEnables(dev_data, dstStageMask, "vkCmdWaitEvents()", VALIDATION_ERROR_02068,
8403208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                                             VALIDATION_ERROR_02070);
8404d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        auto first_event_index = cb_state->events.size();
84055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < eventCount; ++i) {
84069a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto event_state = GetEventNode(dev_data, pEvents[i]);
84074710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis            if (event_state) {
84084710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis                addCommandBufferBinding(&event_state->cb_bindings,
8409ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis                                        {reinterpret_cast<const uint64_t &>(pEvents[i]), VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT},
8410d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                        cb_state);
8411d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                event_state->cb_bindings.insert(cb_state);
8412ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis            }
8413d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski            cb_state->waitedEvents.insert(pEvents[i]);
8414d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski            cb_state->events.push_back(pEvents[i]);
84155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8416d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        std::function<bool(VkQueue)> event_update =
8417d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski            std::bind(validateEventStageMask, std::placeholders::_1, cb_state, eventCount, first_event_index, sourceStageMask);
8418d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        cb_state->eventUpdates.push_back(event_update);
8419baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdWaitEvents()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
8420baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                      VALIDATION_ERROR_00262);
8421ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        skip |= ValidateCmd(dev_data, cb_state, CMD_WAITEVENTS, "vkCmdWaitEvents()");
8422ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        UpdateCmdBufferLastCmd(cb_state, CMD_WAITEVENTS);
8423a90f5fa414aa0994e67cdb911938e6ae48f2ad6aMike Weiblen        skip |=
8424a90f5fa414aa0994e67cdb911938e6ae48f2ad6aMike Weiblen            ValidateBarriersToImages(dev_data, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers, "vkCmdWaitEvents()");
8425e659c986db0f3146726d6c744c75772316c3e0c6Mark Lobodzinski        if (!skip) {
8426e659c986db0f3146726d6c744c75772316c3e0c6Mark Lobodzinski            TransitionImageLayouts(dev_data, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers);
8427e659c986db0f3146726d6c744c75772316c3e0c6Mark Lobodzinski        }
8428e659c986db0f3146726d6c744c75772316c3e0c6Mark Lobodzinski
8429364a03b109f0b2b37be2e13d293fa93b8af5203aMike Weiblen        skip |= ValidateBarriers("vkCmdWaitEvents()", commandBuffer, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
8430d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                 pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
84315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8432b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8433d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    if (!skip)
84344a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdWaitEvents(commandBuffer, eventCount, pEvents, sourceStageMask, dstStageMask,
84354a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                               memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers,
84364a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                               imageMemoryBarrierCount, pImageMemoryBarriers);
84375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
84385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
843903122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinskistatic bool PreCallValidateCmdPipelineBarrier(layer_data *device_data, GLOBAL_CB_NODE *cb_state, VkCommandBuffer commandBuffer,
844003122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                              VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask,
844103122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                              uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
844203122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                              uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
844303122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                              uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
844403122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    bool skip = false;
844503122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    skip |= ValidateStageMasksAgainstQueueCapabilities(device_data, cb_state, srcStageMask, dstStageMask, "vkCmdPipelineBarrier",
844603122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                                       VALIDATION_ERROR_02513);
8447baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    skip |= ValidateCmdQueueFlags(device_data, cb_state, "vkCmdPipelineBarrier()",
8448baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                  VK_QUEUE_TRANSFER_BIT | VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, VALIDATION_ERROR_00280);
844903122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    skip |= ValidateCmd(device_data, cb_state, CMD_PIPELINEBARRIER, "vkCmdPipelineBarrier()");
845003122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    skip |= ValidateStageMaskGsTsEnables(device_data, srcStageMask, "vkCmdPipelineBarrier()", VALIDATION_ERROR_00265,
845103122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                         VALIDATION_ERROR_00267);
845203122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    skip |= ValidateStageMaskGsTsEnables(device_data, dstStageMask, "vkCmdPipelineBarrier()", VALIDATION_ERROR_00266,
845303122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                         VALIDATION_ERROR_00268);
8454a90f5fa414aa0994e67cdb911938e6ae48f2ad6aMike Weiblen    skip |= ValidateBarriersToImages(device_data, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers,
8455a90f5fa414aa0994e67cdb911938e6ae48f2ad6aMike Weiblen                                     "vkCmdPipelineBarrier()");
845603122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    skip |= ValidateBarriers("vkCmdPipelineBarrier()", commandBuffer, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
845703122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                             pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
845803122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    return skip;
845903122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski}
846003122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski
84616f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinskistatic void PreCallRecordCmdPipelineBarrier(layer_data *device_data, GLOBAL_CB_NODE *cb_state, VkCommandBuffer commandBuffer,
84626f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski                                            uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
84636f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski    UpdateCmdBufferLastCmd(cb_state, CMD_PIPELINEBARRIER);
84646f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski    TransitionImageLayouts(device_data, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers);
84656f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski}
84666f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski
8467d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask,
8468d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                              VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags,
8469d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                              uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
8470d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                              uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
8471d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                              uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
8472d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    bool skip = false;
84736f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8474b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
84756f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski    GLOBAL_CB_NODE *cb_state = GetCBNode(device_data, commandBuffer);
8476d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    if (cb_state) {
84776f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski        skip |= PreCallValidateCmdPipelineBarrier(device_data, cb_state, commandBuffer, srcStageMask, dstStageMask,
847803122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                                  memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
847903122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                                  pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
84806f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski        if (!skip) {
84816f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski            PreCallRecordCmdPipelineBarrier(device_data, cb_state, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers);
84826f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski        }
84836f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski    } else {
84846f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski        assert(0);
84855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8486b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8487a79957f762f6fc6b74c25cb94d35a3fc36967471Tony Barbour    if (!skip) {
8488a79957f762f6fc6b74c25cb94d35a3fc36967471Tony Barbour        device_data->dispatch_table.CmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, dependencyFlags, memoryBarrierCount,
8489a79957f762f6fc6b74c25cb94d35a3fc36967471Tony Barbour                                                       pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers,
8490a79957f762f6fc6b74c25cb94d35a3fc36967471Tony Barbour                                                       imageMemoryBarrierCount, pImageMemoryBarriers);
8491a79957f762f6fc6b74c25cb94d35a3fc36967471Tony Barbour    }
84925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
84935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8494d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentinebool setQueryState(VkQueue queue, VkCommandBuffer commandBuffer, QueryObject object, bool value) {
849556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
84969a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
8497d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    if (pCB) {
8498d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        pCB->queryToStateMap[object] = value;
8499d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    }
8500d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    auto queue_data = dev_data->queueMap.find(queue);
8501d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    if (queue_data != dev_data->queueMap.end()) {
8502d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        queue_data->second.queryToStateMap[object] = value;
8503d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    }
8504d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    return false;
8505d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine}
8506d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine
8507bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBeginQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot, VkFlags flags) {
850883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
850956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8510b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
85119a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
85125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
85135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        QueryObject query = {queryPool, slot};
85145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->activeQueries.insert(query);
85155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!pCB->startedQueries.count(query)) {
85165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pCB->startedQueries.insert(query);
85175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8518baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip_call |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdBeginQuery()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
8519baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                           VALIDATION_ERROR_01039);
852029f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_BEGINQUERY, "vkCmdBeginQuery()");
85211ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_BEGINQUERY);
85229a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        addCommandBufferBinding(&GetQueryPoolNode(dev_data, queryPool)->cb_bindings,
8523ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis                                {reinterpret_cast<uint64_t &>(queryPool), VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT}, pCB);
85245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8525b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8526cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdBeginQuery(commandBuffer, queryPool, slot, flags);
85275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
85285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
852989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdEndQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot) {
8530946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
853156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8532b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
8533946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
8534946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (cb_state) {
85355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        QueryObject query = {queryPool, slot};
8536946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        if (!cb_state->activeQueries.count(query)) {
8537df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
8538df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            reinterpret_cast<uint64_t>(commandBuffer), __LINE__, VALIDATION_ERROR_01041, "DS",
8539df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "Ending a query before it was started: queryPool 0x%" PRIx64 ", index %d. %s", (uint64_t)(queryPool),
8540df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            slot, validation_error_map[VALIDATION_ERROR_01041]);
85415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
8542946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            cb_state->activeQueries.erase(query);
85435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8544946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        std::function<bool(VkQueue)> query_update = std::bind(setQueryState, std::placeholders::_1, commandBuffer, query, true);
8545946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        cb_state->queryUpdates.push_back(query_update);
8546baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "VkCmdEndQuery()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
8547baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                      VALIDATION_ERROR_01046);
8548946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_state, CMD_ENDQUERY, "VkCmdEndQuery()");
8549946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        UpdateCmdBufferLastCmd(cb_state, CMD_ENDQUERY);
85509a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        addCommandBufferBinding(&GetQueryPoolNode(dev_data, queryPool)->cb_bindings,
8551946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                {reinterpret_cast<uint64_t &>(queryPool), VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT}, cb_state);
85525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8553b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8554946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdEndQuery(commandBuffer, queryPool, slot);
85555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
85565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8557bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdResetQueryPool(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery,
8558bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                             uint32_t queryCount) {
8559946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
856056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8561b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
8562946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
8563946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (cb_state) {
85645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < queryCount; i++) {
85655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            QueryObject query = {queryPool, firstQuery + i};
8566946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            cb_state->waitedEventsBeforeQueryReset[query] = cb_state->waitedEvents;
8567946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            std::function<bool(VkQueue)> query_update =
8568946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                std::bind(setQueryState, std::placeholders::_1, commandBuffer, query, false);
8569946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            cb_state->queryUpdates.push_back(query_update);
8570946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        }
8571baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "VkCmdResetQueryPool()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
8572baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                      VALIDATION_ERROR_01024);
8573946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_state, CMD_RESETQUERYPOOL, "VkCmdResetQueryPool()");
8574946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        UpdateCmdBufferLastCmd(cb_state, CMD_RESETQUERYPOOL);
8575946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= insideRenderPass(dev_data, cb_state, "vkCmdResetQueryPool()", VALIDATION_ERROR_01025);
85769a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        addCommandBufferBinding(&GetQueryPoolNode(dev_data, queryPool)->cb_bindings,
8577946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                {reinterpret_cast<uint64_t &>(queryPool), VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT}, cb_state);
85785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8579b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8580946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdResetQueryPool(commandBuffer, queryPool, firstQuery, queryCount);
85815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
85825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8583d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentinebool validateQuery(VkQueue queue, GLOBAL_CB_NODE *pCB, VkQueryPool queryPool, uint32_t queryCount, uint32_t firstQuery) {
8584d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    bool skip_call = false;
858556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(pCB->commandBuffer), layer_data_map);
8586d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    auto queue_data = dev_data->queueMap.find(queue);
8587cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (queue_data == dev_data->queueMap.end()) return false;
8588d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    for (uint32_t i = 0; i < queryCount; i++) {
8589d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        QueryObject query = {queryPool, firstQuery + i};
8590d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        auto query_data = queue_data->second.queryToStateMap.find(query);
8591d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        bool fail = false;
8592d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        if (query_data != queue_data->second.queryToStateMap.end()) {
8593d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            if (!query_data->second) {
8594d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                fail = true;
8595d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            }
8596d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        } else {
8597d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            auto global_query_data = dev_data->queryToStateMap.find(query);
8598d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            if (global_query_data != dev_data->queryToStateMap.end()) {
8599d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                if (!global_query_data->second) {
8600d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                    fail = true;
8601d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                }
8602d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            } else {
8603d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                fail = true;
8604d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            }
8605d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        }
8606d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        if (fail) {
8607df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip_call |=
8608df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
8609df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        reinterpret_cast<uint64_t>(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
8610df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        "Requesting a copy from query to buffer with invalid query: queryPool 0x%" PRIx64 ", index %d",
8611df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        reinterpret_cast<uint64_t &>(queryPool), firstQuery + i);
8612d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        }
8613d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    }
8614d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    return skip_call;
8615d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine}
8616d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine
8617bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdCopyQueryPoolResults(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery,
8618bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset,
8619bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   VkDeviceSize stride, VkQueryResultFlags flags) {
8620946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
862156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8622b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
8623ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
86249a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
86259a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto dst_buff_state = GetBufferState(dev_data, dstBuffer);
86265cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (cb_node && dst_buff_state) {
8627946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateMemoryIsBoundToBuffer(dev_data, dst_buff_state, "vkCmdCopyQueryPoolResults()", VALIDATION_ERROR_02526);
8628ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Update bindings between buffer and cmd buffer
86295cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        AddCommandBufferBindingBuffer(dev_data, cb_node, dst_buff_state);
8630ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Validate that DST buffer has correct usage flags set
8631946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateBufferUsageFlags(dev_data, dst_buff_state, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, VALIDATION_ERROR_01066,
8632946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                         "vkCmdCopyQueryPoolResults()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
8633e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
86345cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            SetBufferMemoryValid(dev_data, dst_buff_state, true);
8635e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
86365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        };
86379f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
8638946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        std::function<bool(VkQueue)> query_update =
8639ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis            std::bind(validateQuery, std::placeholders::_1, cb_node, queryPool, queryCount, firstQuery);
8640946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        cb_node->queryUpdates.push_back(query_update);
8641baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_node, "vkCmdCopyQueryPoolResults()",
8642baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                      VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, VALIDATION_ERROR_01073);
8643946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_node, CMD_COPYQUERYPOOLRESULTS, "vkCmdCopyQueryPoolResults()");
8644ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        UpdateCmdBufferLastCmd(cb_node, CMD_COPYQUERYPOOLRESULTS);
8645946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= insideRenderPass(dev_data, cb_node, "vkCmdCopyQueryPoolResults()", VALIDATION_ERROR_01074);
86469a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        addCommandBufferBinding(&GetQueryPoolNode(dev_data, queryPool)->cb_bindings,
8647ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis                                {reinterpret_cast<uint64_t &>(queryPool), VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT}, cb_node);
8648ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
8649ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
86505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8651b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8652946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip)
86534a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdCopyQueryPoolResults(commandBuffer, queryPool, firstQuery, queryCount, dstBuffer, dstOffset,
86544a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                         stride, flags);
86555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
86565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8657bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdPushConstants(VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags,
8658bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                            uint32_t offset, uint32_t size, const void *pValues) {
8659946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
866056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8661b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
8662946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
8663946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (cb_state) {
8664baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdPushConstants()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
8665baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                      VALIDATION_ERROR_00999);
8666946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_state, CMD_PUSHCONSTANTS, "vkCmdPushConstants()");
8667946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        UpdateCmdBufferLastCmd(cb_state, CMD_PUSHCONSTANTS);
86685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8669946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    skip |= validatePushConstantRange(dev_data, offset, size, "vkCmdPushConstants()");
86709e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    if (0 == stageFlags) {
8671df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
8672df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        reinterpret_cast<uint64_t>(commandBuffer), __LINE__, VALIDATION_ERROR_00996, "DS",
8673df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        "vkCmdPushConstants() call has no stageFlags set. %s", validation_error_map[VALIDATION_ERROR_00996]);
86749e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    }
86759e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz
8676bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz    // Check if specified push constant range falls within a pipeline-defined range which has matching stageFlags.
8677bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz    // The spec doesn't seem to disallow having multiple push constant ranges with the
8678bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz    // same offset and size, but different stageFlags.  So we can't just check the
8679bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz    // stageFlags in the first range with matching offset and size.
8680bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz    if (!skip) {
8681bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz        const auto &ranges = getPipelineLayout(dev_data, layout)->push_constant_ranges;
8682bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz        bool found_matching_range = false;
8683bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz        for (const auto &range : ranges) {
8684bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz            if ((stageFlags == range.stageFlags) && (offset >= range.offset) && (offset + size <= range.offset + range.size)) {
8685bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz                found_matching_range = true;
868615a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                break;
8687a95cb74c9d0947ab3821b15e1289755286ea78eeKarl Schultz            }
86889e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
8689bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz        if (!found_matching_range) {
8690df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
8691df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            reinterpret_cast<uint64_t>(commandBuffer), __LINE__, VALIDATION_ERROR_00988, "DS",
8692df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "vkCmdPushConstants() stageFlags = 0x%" PRIx32
8693df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            " do not match the stageFlags in any of the ranges with"
8694df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            " offset = %d and size = %d in pipeline layout 0x%" PRIx64 ". %s",
8695bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz                            (uint32_t)stageFlags, offset, size, (uint64_t)layout, validation_error_map[VALIDATION_ERROR_00988]);
869615a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        }
86975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8698b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8699946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdPushConstants(commandBuffer, layout, stageFlags, offset, size, pValues);
87005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
87015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8702bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage,
8703bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                             VkQueryPool queryPool, uint32_t slot) {
8704946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
870556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8706b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
8707946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
8708946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (cb_state) {
87095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        QueryObject query = {queryPool, slot};
8710946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        std::function<bool(VkQueue)> query_update = std::bind(setQueryState, std::placeholders::_1, commandBuffer, query, true);
8711946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        cb_state->queryUpdates.push_back(query_update);
8712baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdWriteTimestamp()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
8713baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                      VALIDATION_ERROR_01082);
8714946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_state, CMD_WRITETIMESTAMP, "vkCmdWriteTimestamp()");
8715946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        UpdateCmdBufferLastCmd(cb_state, CMD_WRITETIMESTAMP);
87165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8717b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8718946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdWriteTimestamp(commandBuffer, pipelineStage, queryPool, slot);
87195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
87205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
87216600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinskistatic bool MatchUsage(layer_data *dev_data, uint32_t count, const VkAttachmentReference *attachments,
87229bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                       const VkFramebufferCreateInfo *fbci, VkImageUsageFlagBits usage_flag,
87239bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                       UNIQUE_VALIDATION_ERROR_CODE error_code) {
8724946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
87256600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
87266600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    for (uint32_t attach = 0; attach < count; attach++) {
87276600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski        if (attachments[attach].attachment != VK_ATTACHMENT_UNUSED) {
87286600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            // Attachment counts are verified elsewhere, but prevent an invalid access
87296600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            if (attachments[attach].attachment < fbci->attachmentCount) {
87306600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                const VkImageView *image_view = &fbci->pAttachments[attachments[attach].attachment];
87319a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto view_state = GetImageViewState(dev_data, *image_view);
873279fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if (view_state) {
87339a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    const VkImageCreateInfo *ici = &GetImageState(dev_data, view_state->create_info.image)->createInfo;
87346600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                    if (ici != nullptr) {
87356600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                        if ((ici->usage & usage_flag) == 0) {
8736df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
8737df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                            VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, error_code, "DS",
8738946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                            "vkCreateFramebuffer:  Framebuffer Attachment (%d) conflicts with the image's "
8739946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                            "IMAGE_USAGE flags (%s). %s",
8740946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                            attachments[attach].attachment, string_VkImageUsageFlagBits(usage_flag),
8741946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                            validation_error_map[error_code]);
87426600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                        }
87436600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                    }
87446600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                }
87456600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            }
87466600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski        }
87476600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    }
8748946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    return skip;
87496600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski}
87506600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
8751d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis// Validate VkFramebufferCreateInfo which includes:
8752d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis// 1. attachmentCount equals renderPass attachmentCount
87535ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 2. corresponding framebuffer and renderpass attachments have matching formats
87545ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 3. corresponding framebuffer and renderpass attachments have matching sample counts
87555ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 4. fb attachments only have a single mip level
87565ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 5. fb attachment dimensions are each at least as large as the fb
87575ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 6. fb attachments use idenity swizzle
87585ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 7. fb attachments used by renderPass for color/input/ds have correct usage bit set
87596fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis// 8. fb dimensions are within physical device limits
8760d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlisstatic bool ValidateFramebufferCreateInfo(layer_data *dev_data, const VkFramebufferCreateInfo *pCreateInfo) {
87616600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    bool skip_call = false;
87626600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
87639a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto rp_state = GetRenderPassState(dev_data, pCreateInfo->renderPass);
8764127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis    if (rp_state) {
8765127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis        const VkRenderPassCreateInfo *rpci = rp_state->createInfo.ptr();
8766d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis        if (rpci->attachmentCount != pCreateInfo->attachmentCount) {
8767d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis            skip_call |= log_msg(
8768d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
87699bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                reinterpret_cast<const uint64_t &>(pCreateInfo->renderPass), __LINE__, VALIDATION_ERROR_00404, "DS",
8770d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis                "vkCreateFramebuffer(): VkFramebufferCreateInfo attachmentCount of %u does not match attachmentCount of %u of "
87719bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                "renderPass (0x%" PRIxLEAST64 ") being used to create Framebuffer. %s",
87729bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                pCreateInfo->attachmentCount, rpci->attachmentCount, reinterpret_cast<const uint64_t &>(pCreateInfo->renderPass),
87739bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                validation_error_map[VALIDATION_ERROR_00404]);
87745ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis        } else {
877541ebcb6b517b1de5ae456d46d866f5e84a96a2c5Tobin Ehlis            // attachmentCounts match, so make sure corresponding attachment details line up
87765ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis            const VkImageView *image_views = pCreateInfo->pAttachments;
87775ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis            for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
87789a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto view_state = GetImageViewState(dev_data, image_views[i]);
877912d5600c2f9e32343016fd944432ba95df370797Tobin Ehlis                auto &ivci = view_state->create_info;
878079fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if (ivci.format != rpci->pAttachments[i].format) {
87815ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                    skip_call |= log_msg(
87825ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
87839bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        reinterpret_cast<const uint64_t &>(pCreateInfo->renderPass), __LINE__, VALIDATION_ERROR_00408, "DS",
87849bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has format of %s that does not match "
87859bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "the format of "
87869bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "%s used by the corresponding attachment for renderPass (0x%" PRIxLEAST64 "). %s",
878779fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                        i, string_VkFormat(ivci.format), string_VkFormat(rpci->pAttachments[i].format),
87889bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        reinterpret_cast<const uint64_t &>(pCreateInfo->renderPass), validation_error_map[VALIDATION_ERROR_00408]);
87895ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
87909a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                const VkImageCreateInfo *ici = &GetImageState(dev_data, ivci.image)->createInfo;
87915ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                if (ici->samples != rpci->pAttachments[i].samples) {
879241ebcb6b517b1de5ae456d46d866f5e84a96a2c5Tobin Ehlis                    skip_call |= log_msg(
879341ebcb6b517b1de5ae456d46d866f5e84a96a2c5Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
87949bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        reinterpret_cast<const uint64_t &>(pCreateInfo->renderPass), __LINE__, VALIDATION_ERROR_00409, "DS",
87959bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has %s samples that do not match "
87969bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "the %s samples used by the corresponding attachment for renderPass (0x%" PRIxLEAST64 "). %s",
879741ebcb6b517b1de5ae456d46d866f5e84a96a2c5Tobin Ehlis                        i, string_VkSampleCountFlagBits(ici->samples), string_VkSampleCountFlagBits(rpci->pAttachments[i].samples),
87989bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        reinterpret_cast<const uint64_t &>(pCreateInfo->renderPass), validation_error_map[VALIDATION_ERROR_00409]);
87995ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
88005ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                // Verify that view only has a single mip level
880179fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if (ivci.subresourceRange.levelCount != 1) {
88029bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                    skip_call |=
88039bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
88049bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                VALIDATION_ERROR_00411, "DS",
88059bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has mip levelCount of %u "
88069bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                "but only a single mip level (levelCount ==  1) is allowed when creating a Framebuffer. %s",
88079bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                i, ivci.subresourceRange.levelCount, validation_error_map[VALIDATION_ERROR_00411]);
88085ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
880979fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                const uint32_t mip_level = ivci.subresourceRange.baseMipLevel;
8810aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                uint32_t mip_width = max(1u, ici->extent.width >> mip_level);
8811aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                uint32_t mip_height = max(1u, ici->extent.height >> mip_level);
881279fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if ((ivci.subresourceRange.layerCount < pCreateInfo->layers) || (mip_width < pCreateInfo->width) ||
8813aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                    (mip_height < pCreateInfo->height)) {
8814aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                    skip_call |=
88156fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
8816aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                DRAWSTATE_INVALID_FRAMEBUFFER_CREATE_INFO, "DS",
8817aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u mip level %u has dimensions smaller "
8818aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                "than the corresponding "
8819aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                "framebuffer dimensions. Attachment dimensions must be at least as large. Here are the respective "
8820aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                "dimensions for "
8821aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                "attachment #%u, framebuffer:\n"
8822aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                "width: %u, %u\n"
8823aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                "height: %u, %u\n"
8824aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                                "layerCount: %u, %u\n",
882579fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                                i, ivci.subresourceRange.baseMipLevel, i, mip_width, pCreateInfo->width, mip_height,
882679fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                                pCreateInfo->height, ivci.subresourceRange.layerCount, pCreateInfo->layers);
88275ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
882879fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if (((ivci.components.r != VK_COMPONENT_SWIZZLE_IDENTITY) && (ivci.components.r != VK_COMPONENT_SWIZZLE_R)) ||
882979fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                    ((ivci.components.g != VK_COMPONENT_SWIZZLE_IDENTITY) && (ivci.components.g != VK_COMPONENT_SWIZZLE_G)) ||
883079fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                    ((ivci.components.b != VK_COMPONENT_SWIZZLE_IDENTITY) && (ivci.components.b != VK_COMPONENT_SWIZZLE_B)) ||
883179fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                    ((ivci.components.a != VK_COMPONENT_SWIZZLE_IDENTITY) && (ivci.components.a != VK_COMPONENT_SWIZZLE_A))) {
8832da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                    skip_call |= log_msg(
88336fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
88349bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        VALIDATION_ERROR_00412, "DS",
8835da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has non-identy swizzle. All framebuffer "
8836da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "attachments must have been created with the identity swizzle. Here are the actual swizzle values:\n"
8837da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "r swizzle = %s\n"
8838da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "g swizzle = %s\n"
8839da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "b swizzle = %s\n"
88409bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "a swizzle = %s\n"
88419bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "%s",
884279fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                        i, string_VkComponentSwizzle(ivci.components.r), string_VkComponentSwizzle(ivci.components.g),
88439bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        string_VkComponentSwizzle(ivci.components.b), string_VkComponentSwizzle(ivci.components.a),
88449bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        validation_error_map[VALIDATION_ERROR_00412]);
88455ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
88465ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis            }
8847d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis        }
88485ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis        // Verify correct attachment usage flags
88496600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski        for (uint32_t subpass = 0; subpass < rpci->subpassCount; subpass++) {
88506600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            // Verify input attachments:
88519bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt            skip_call |=
88529bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                MatchUsage(dev_data, rpci->pSubpasses[subpass].inputAttachmentCount, rpci->pSubpasses[subpass].pInputAttachments,
88539bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                           pCreateInfo, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, VALIDATION_ERROR_00407);
88546600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            // Verify color attachments:
88559bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt            skip_call |=
88569bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                MatchUsage(dev_data, rpci->pSubpasses[subpass].colorAttachmentCount, rpci->pSubpasses[subpass].pColorAttachments,
88579bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                           pCreateInfo, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VALIDATION_ERROR_00405);
88586600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            // Verify depth/stencil attachments:
88596600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            if (rpci->pSubpasses[subpass].pDepthStencilAttachment != nullptr) {
88606600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                skip_call |= MatchUsage(dev_data, 1, rpci->pSubpasses[subpass].pDepthStencilAttachment, pCreateInfo,
88619bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                        VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VALIDATION_ERROR_00406);
88626600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            }
88636600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski        }
88646600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    }
88656fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis    // Verify FB dimensions are within physical device limits
88669bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    if (pCreateInfo->width > dev_data->phys_dev_properties.properties.limits.maxFramebufferWidth) {
88676fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
88689bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             VALIDATION_ERROR_00413, "DS",
88699bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo width exceeds physical device limits. "
88709bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "Requested width: %u, device max: %u\n"
88719bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "%s",
88726fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis                             pCreateInfo->width, dev_data->phys_dev_properties.properties.limits.maxFramebufferWidth,
88739bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             validation_error_map[VALIDATION_ERROR_00413]);
88749bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    }
88759bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    if (pCreateInfo->height > dev_data->phys_dev_properties.properties.limits.maxFramebufferHeight) {
88769bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
88779bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             VALIDATION_ERROR_00414, "DS",
88789bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo height exceeds physical device limits. "
88799bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "Requested height: %u, device max: %u\n"
88809bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "%s",
88816fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis                             pCreateInfo->height, dev_data->phys_dev_properties.properties.limits.maxFramebufferHeight,
88829bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             validation_error_map[VALIDATION_ERROR_00414]);
88839bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    }
88849bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    if (pCreateInfo->layers > dev_data->phys_dev_properties.properties.limits.maxFramebufferLayers) {
88859bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
88869bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             VALIDATION_ERROR_00415, "DS",
88879bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo layers exceeds physical device limits. "
88889bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "Requested layers: %u, device max: %u\n"
88899bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             "%s",
88909bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             pCreateInfo->layers, dev_data->phys_dev_properties.properties.limits.maxFramebufferLayers,
88919bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             validation_error_map[VALIDATION_ERROR_00415]);
88926fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis    }
88936600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    return skip_call;
88946600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski}
88956600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
889664c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis// Validate VkFramebufferCreateInfo state prior to calling down chain to create Framebuffer object
889764c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis//  Return true if an error is encountered and callback returns true to skip call down chain
889864c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis//   false indicates that call down chain should proceed
889964c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlisstatic bool PreCallValidateCreateFramebuffer(layer_data *dev_data, const VkFramebufferCreateInfo *pCreateInfo) {
890064c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    // TODO : Verify that renderPass FB is created with is compatible with FB
890164c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    bool skip_call = false;
8902d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis    skip_call |= ValidateFramebufferCreateInfo(dev_data, pCreateInfo);
890364c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    return skip_call;
890464c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis}
890564c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis
890654e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis// CreateFramebuffer state has been validated and call down chain completed so record new framebuffer object
890754e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlisstatic void PostCallRecordCreateFramebuffer(layer_data *dev_data, const VkFramebufferCreateInfo *pCreateInfo, VkFramebuffer fb) {
890854e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis    // Shadow create info and store in map
8909c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    std::unique_ptr<FRAMEBUFFER_STATE> fb_state(
8910c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis        new FRAMEBUFFER_STATE(fb, pCreateInfo, dev_data->renderPassMap[pCreateInfo->renderPass]->createInfo.ptr()));
891176f04ca0e692f9f15d5ef7e0c658c24d11f34ebcTobin Ehlis
891254e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
891354e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        VkImageView view = pCreateInfo->pAttachments[i];
89149a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto view_state = GetImageViewState(dev_data, view);
891579fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis        if (!view_state) {
891654e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis            continue;
891754e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        }
891854e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        MT_FB_ATTACHMENT_INFO fb_info;
89199a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        fb_info.mem = GetImageState(dev_data, view_state->create_info.image)->binding.mem;
8920883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        fb_info.view_state = view_state;
892179fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis        fb_info.image = view_state->create_info.image;
8922c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis        fb_state->attachments.push_back(fb_info);
892354e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis    }
8924c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    dev_data->frameBufferMap[fb] = std::move(fb_state);
892554e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis}
892654e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis
892789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateFramebuffer(VkDevice device, const VkFramebufferCreateInfo *pCreateInfo,
8928bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkAllocationCallbacks *pAllocator, VkFramebuffer *pFramebuffer) {
892956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
893064c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
893164c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    bool skip_call = PreCallValidateCreateFramebuffer(dev_data, pCreateInfo);
893264c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    lock.unlock();
893364c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis
8934cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
893564c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis
89364a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateFramebuffer(device, pCreateInfo, pAllocator, pFramebuffer);
89376600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
89385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
893964c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis        lock.lock();
894054e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        PostCallRecordCreateFramebuffer(dev_data, pCreateInfo, *pFramebuffer);
894154e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        lock.unlock();
89425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
89435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
89445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
89455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
89464e11bb1277f55311686a42000520791e1db1dd7bbungemanstatic bool FindDependency(const uint32_t index, const uint32_t dependent, const std::vector<DAGNode> &subpass_to_node,
8947e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                           std::unordered_set<uint32_t> &processed_nodes) {
89485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If we have already checked this node we have not found a dependency path so return false.
8949cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (processed_nodes.count(index)) return false;
89505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    processed_nodes.insert(index);
89515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    const DAGNode &node = subpass_to_node[index];
89525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Look for a dependency path. If one exists return true else recurse on the previous nodes.
89534e11bb1277f55311686a42000520791e1db1dd7bbungeman    if (std::find(node.prev.begin(), node.prev.end(), dependent) == node.prev.end()) {
89545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto elem : node.prev) {
8955cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (FindDependency(elem, dependent, subpass_to_node, processed_nodes)) return true;
89565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
89575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
8958e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        return true;
89595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8960e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    return false;
89615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
89625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
89634e11bb1277f55311686a42000520791e1db1dd7bbungemanstatic bool CheckDependencyExists(const layer_data *dev_data, const uint32_t subpass,
89644e11bb1277f55311686a42000520791e1db1dd7bbungeman                                  const std::vector<uint32_t> &dependent_subpasses,
8965e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                                  const std::vector<DAGNode> &subpass_to_node, bool &skip_call) {
8966e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool result = true;
89675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Loop through all subpasses that share the same attachment and make sure a dependency exists
89685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t k = 0; k < dependent_subpasses.size(); ++k) {
8969cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (static_cast<uint32_t>(subpass) == dependent_subpasses[k]) continue;
89705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const DAGNode &node = subpass_to_node[subpass];
89715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Check for a specified dependency between the two nodes. If one exists we are done.
89725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto prev_elem = std::find(node.prev.begin(), node.prev.end(), dependent_subpasses[k]);
89735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto next_elem = std::find(node.next.begin(), node.next.end(), dependent_subpasses[k]);
89745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (prev_elem == node.prev.end() && next_elem == node.next.end()) {
89757655cb8b5eb52badee0b011729a05afa36316d69Jan-Harald Fredriksen            // If no dependency exits an implicit dependency still might. If not, throw an error.
89765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            std::unordered_set<uint32_t> processed_nodes;
89777655cb8b5eb52badee0b011729a05afa36316d69Jan-Harald Fredriksen            if (!(FindDependency(subpass, dependent_subpasses[k], subpass_to_node, processed_nodes) ||
8978bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                  FindDependency(dependent_subpasses[k], subpass, subpass_to_node, processed_nodes))) {
8979df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
8980df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                     0, __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
89815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                     "A dependency between subpasses %d and %d must exist but one is not specified.", subpass,
89825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                     dependent_subpasses[k]);
8983e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                result = false;
89845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
89855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
89865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
89875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
89885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
89895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
89908860b85a52096f9f9b28616bc37feed505497a54Chris Forbesstatic bool CheckPreserved(const layer_data *dev_data, const VkRenderPassCreateInfo *pCreateInfo, const int index,
8991e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                           const uint32_t attachment, const std::vector<DAGNode> &subpass_to_node, int depth, bool &skip_call) {
89925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    const DAGNode &node = subpass_to_node[index];
89935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If this node writes to the attachment return true as next nodes need to preserve the attachment.
89945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[index];
89955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
8996cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (attachment == subpass.pColorAttachments[j].attachment) return true;
89975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8998a4ea781e8fff70c9db0bedad7fcb6bba08e35da7Tony Barbour    for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
8999a4ea781e8fff70c9db0bedad7fcb6bba08e35da7Tony Barbour        if (attachment == subpass.pInputAttachments[j].attachment) return true;
9000a4ea781e8fff70c9db0bedad7fcb6bba08e35da7Tony Barbour    }
90015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
9002cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (attachment == subpass.pDepthStencilAttachment->attachment) return true;
90035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9004e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool result = false;
90055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Loop through previous nodes and see if any of them write to the attachment.
90065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto elem : node.prev) {
90078860b85a52096f9f9b28616bc37feed505497a54Chris Forbes        result |= CheckPreserved(dev_data, pCreateInfo, elem, attachment, subpass_to_node, depth + 1, skip_call);
90085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
90095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If the attachment was written to by a previous node than this node needs to preserve it.
90105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result && depth > 0) {
9011e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        bool has_preserved = false;
90125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.preserveAttachmentCount; ++j) {
90135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (subpass.pPreserveAttachments[j] == attachment) {
9014e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                has_preserved = true;
90155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                break;
90165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
90175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
9018e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        if (!has_preserved) {
90195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            skip_call |=
9020df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
90215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        DRAWSTATE_INVALID_RENDERPASS, "DS",
90225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        "Attachment %d is used by a later subpass and must be preserved in subpass %d.", attachment, index);
90235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
90245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
90255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
90265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
90275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9028cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskitemplate <class T>
9029cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskibool isRangeOverlapping(T offset1, T size1, T offset2, T size2) {
90305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return (((offset1 + size1) > offset2) && ((offset1 + size1) < (offset2 + size2))) ||
90315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis           ((offset1 > offset2) && (offset1 < (offset2 + size2)));
90325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
90335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
90345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisbool isRegionOverlapping(VkImageSubresourceRange range1, VkImageSubresourceRange range2) {
90355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return (isRangeOverlapping(range1.baseMipLevel, range1.levelCount, range2.baseMipLevel, range2.levelCount) &&
90365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            isRangeOverlapping(range1.baseArrayLayer, range1.layerCount, range2.baseArrayLayer, range2.layerCount));
90375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
90385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9039c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlisstatic bool ValidateDependencies(const layer_data *dev_data, FRAMEBUFFER_STATE const *framebuffer,
9040127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                                 RENDER_PASS_STATE const *renderPass) {
9041e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
9042fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    auto const pFramebufferInfo = framebuffer->createInfo.ptr();
9043fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    auto const pCreateInfo = renderPass->createInfo.ptr();
9044bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto const &subpass_to_node = renderPass->subpassToNode;
90455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<std::vector<uint32_t>> output_attachment_to_subpass(pCreateInfo->attachmentCount);
90465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<std::vector<uint32_t>> input_attachment_to_subpass(pCreateInfo->attachmentCount);
90475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<std::vector<uint32_t>> overlapping_attachments(pCreateInfo->attachmentCount);
90485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Find overlapping attachments
90495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
90505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = i + 1; j < pCreateInfo->attachmentCount; ++j) {
90515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            VkImageView viewi = pFramebufferInfo->pAttachments[i];
90525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            VkImageView viewj = pFramebufferInfo->pAttachments[j];
90535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (viewi == viewj) {
90545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[i].push_back(j);
90555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[j].push_back(i);
90565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                continue;
90575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
90589a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto view_state_i = GetImageViewState(dev_data, viewi);
90599a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto view_state_j = GetImageViewState(dev_data, viewj);
906079fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis            if (!view_state_i || !view_state_j) {
90615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                continue;
90625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
906379fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis            auto view_ci_i = view_state_i->create_info;
906479fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis            auto view_ci_j = view_state_j->create_info;
906579fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis            if (view_ci_i.image == view_ci_j.image && isRegionOverlapping(view_ci_i.subresourceRange, view_ci_j.subresourceRange)) {
90665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[i].push_back(j);
90675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[j].push_back(i);
90685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                continue;
90695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
90709a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto image_data_i = GetImageState(dev_data, view_ci_i.image);
90719a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto image_data_j = GetImageState(dev_data, view_ci_j.image);
90726d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            if (!image_data_i || !image_data_j) {
90735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                continue;
90745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
9075e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis            if (image_data_i->binding.mem == image_data_j->binding.mem &&
9076e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis                isRangeOverlapping(image_data_i->binding.offset, image_data_i->binding.size, image_data_j->binding.offset,
9077e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis                                   image_data_j->binding.size)) {
90785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[i].push_back(j);
90795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[j].push_back(i);
90805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
90815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
90825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
90835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < overlapping_attachments.size(); ++i) {
90845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t attachment = i;
90855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto other_attachment : overlapping_attachments[i]) {
90865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!(pCreateInfo->pAttachments[attachment].flags & VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT)) {
9087df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                skip_call |=
9088df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT,
9089df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            reinterpret_cast<const uint64_t &>(framebuffer->framebuffer), __LINE__, VALIDATION_ERROR_00324, "DS",
9090df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "Attachment %d aliases attachment %d but doesn't "
9091df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "set VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT. %s",
9092df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            attachment, other_attachment, validation_error_map[VALIDATION_ERROR_00324]);
90935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
90945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!(pCreateInfo->pAttachments[other_attachment].flags & VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT)) {
9095df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                skip_call |=
9096df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT,
9097df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            reinterpret_cast<const uint64_t &>(framebuffer->framebuffer), __LINE__, VALIDATION_ERROR_00324, "DS",
9098df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "Attachment %d aliases attachment %d but doesn't "
9099df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "set VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT. %s",
9100df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            other_attachment, attachment, validation_error_map[VALIDATION_ERROR_00324]);
91015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
91025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
91035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
91045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Find for each attachment the subpasses that use them.
91051c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young    unordered_set<uint32_t> attachmentIndices;
91065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
91075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
91081c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young        attachmentIndices.clear();
91095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
91105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t attachment = subpass.pInputAttachments[j].attachment;
9111cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) continue;
91125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            input_attachment_to_subpass[attachment].push_back(i);
91135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            for (auto overlapping_attachment : overlapping_attachments[attachment]) {
91145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                input_attachment_to_subpass[overlapping_attachment].push_back(i);
91155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
91165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
91175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
91185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t attachment = subpass.pColorAttachments[j].attachment;
9119cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) continue;
91205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            output_attachment_to_subpass[attachment].push_back(i);
91215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            for (auto overlapping_attachment : overlapping_attachments[attachment]) {
91225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                output_attachment_to_subpass[overlapping_attachment].push_back(i);
91235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
91241c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young            attachmentIndices.insert(attachment);
91255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
91265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
91275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t attachment = subpass.pDepthStencilAttachment->attachment;
91285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            output_attachment_to_subpass[attachment].push_back(i);
91295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            for (auto overlapping_attachment : overlapping_attachments[attachment]) {
91305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                output_attachment_to_subpass[overlapping_attachment].push_back(i);
91315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
91321c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young
91331c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young            if (attachmentIndices.count(attachment)) {
91341c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young                skip_call |=
9135df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
9136df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
91378860b85a52096f9f9b28616bc37feed505497a54Chris Forbes                            "Cannot use same attachment (%u) as both color and depth output in same subpass (%u).", attachment, i);
91381c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young            }
91395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
91405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
91415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If there is a dependency needed make sure one exists
91425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
91435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
91445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // If the attachment is an input then all subpasses that output must have a dependency relationship
91455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
914693fe72ec8460857bdb3c101095e6eb96d6171341Chris Forbes            uint32_t attachment = subpass.pInputAttachments[j].attachment;
9147cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) continue;
91488860b85a52096f9f9b28616bc37feed505497a54Chris Forbes            CheckDependencyExists(dev_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip_call);
91495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
91505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // If the attachment is an output then all subpasses that use the attachment must have a dependency relationship
91515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
915293fe72ec8460857bdb3c101095e6eb96d6171341Chris Forbes            uint32_t attachment = subpass.pColorAttachments[j].attachment;
9153cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) continue;
91548860b85a52096f9f9b28616bc37feed505497a54Chris Forbes            CheckDependencyExists(dev_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip_call);
91558860b85a52096f9f9b28616bc37feed505497a54Chris Forbes            CheckDependencyExists(dev_data, i, input_attachment_to_subpass[attachment], subpass_to_node, skip_call);
91565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
91575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
91585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            const uint32_t &attachment = subpass.pDepthStencilAttachment->attachment;
91598860b85a52096f9f9b28616bc37feed505497a54Chris Forbes            CheckDependencyExists(dev_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip_call);
91608860b85a52096f9f9b28616bc37feed505497a54Chris Forbes            CheckDependencyExists(dev_data, i, input_attachment_to_subpass[attachment], subpass_to_node, skip_call);
91615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
91625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
91635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Loop through implicit dependencies, if this pass reads make sure the attachment is preserved for all passes after it was
91645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // written.
91655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
91665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
91675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
91688860b85a52096f9f9b28616bc37feed505497a54Chris Forbes            CheckPreserved(dev_data, pCreateInfo, i, subpass.pInputAttachments[j].attachment, subpass_to_node, 0, skip_call);
91695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
91705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
91715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
91725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
91735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
91748860b85a52096f9f9b28616bc37feed505497a54Chris Forbesstatic bool CreatePassDAG(const layer_data *dev_data, VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
9175e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                          std::vector<DAGNode> &subpass_to_node, std::vector<bool> &has_self_dependency) {
9176e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
91775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
91785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        DAGNode &subpass_node = subpass_to_node[i];
91795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        subpass_node.pass = i;
91805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
91815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->dependencyCount; ++i) {
91825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubpassDependency &dependency = pCreateInfo->pDependencies[i];
918366a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes        if (dependency.srcSubpass == VK_SUBPASS_EXTERNAL || dependency.dstSubpass == VK_SUBPASS_EXTERNAL) {
918466a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes            if (dependency.srcSubpass == dependency.dstSubpass) {
918566a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes                skip_call |=
9186df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
9187df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS", "The src and dest subpasses cannot both be external.");
918866a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes            }
918966a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes        } else if (dependency.srcSubpass > dependency.dstSubpass) {
9190df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
9191df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                 __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
91925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                 "Depedency graph must be specified such that an earlier pass cannot depend on a later pass.");
91935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (dependency.srcSubpass == dependency.dstSubpass) {
91945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            has_self_dependency[dependency.srcSubpass] = true;
91955c6aacf95832467d52b2fde1130b04bef559573aChris Forbes        } else {
91965c6aacf95832467d52b2fde1130b04bef559573aChris Forbes            subpass_to_node[dependency.dstSubpass].prev.push_back(dependency.srcSubpass);
91975c6aacf95832467d52b2fde1130b04bef559573aChris Forbes            subpass_to_node[dependency.srcSubpass].next.push_back(dependency.dstSubpass);
91985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
91995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
92005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
92015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
9202918c283ac4f8c604b79abd0c8b5706d2a7352a34Chris Forbes
920389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo,
9204bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                  const VkAllocationCallbacks *pAllocator, VkShaderModule *pShaderModule) {
920556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
9206e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
9207c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski    spv_result_t spv_valid = SPV_SUCCESS;
9208b1f65702539fd041337fccd493dc6d38dd2a603eChris Forbes
9209e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski    if (!GetDisables(dev_data)->shader_validation) {
9210e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski        // Use SPIRV-Tools validator to try and catch any issues with the module itself
9211e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski        spv_context ctx = spvContextCreate(SPV_ENV_VULKAN_1_0);
9212e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski        spv_const_binary_t binary{pCreateInfo->pCode, pCreateInfo->codeSize / sizeof(uint32_t)};
9213e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski        spv_diagnostic diag = nullptr;
9214b1f65702539fd041337fccd493dc6d38dd2a603eChris Forbes
9215c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski        spv_valid = spvValidate(ctx, &binary, &diag);
9216c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski        if (spv_valid != SPV_SUCCESS) {
92175581a92674a04d2ef49fde417e657f64e3aeed69Mark Lobodzinski            if (!dev_data->device_extensions.nv_glsl_shader_enabled || (pCreateInfo->pCode[0] == spv::MagicNumber)) {
9218c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski                skip_call |= log_msg(dev_data->report_data,
9219c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski                    spv_valid == SPV_WARNING ? VK_DEBUG_REPORT_WARNING_BIT_EXT : VK_DEBUG_REPORT_ERROR_BIT_EXT,
9220c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski                    VkDebugReportObjectTypeEXT(0), 0, __LINE__, SHADER_CHECKER_INCONSISTENT_SPIRV, "SC",
9221c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski                    "SPIR-V module not valid: %s", diag && diag->error ? diag->error : "(no error text)");
9222c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski            }
9223e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski        }
92245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9225e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski        spvDiagnosticDestroy(diag);
9226e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski        spvContextDestroy(ctx);
9227b1f65702539fd041337fccd493dc6d38dd2a603eChris Forbes
9228e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski        if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
9229e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski    }
92305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
92314a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult res = dev_data->dispatch_table.CreateShaderModule(device, pCreateInfo, pAllocator, pShaderModule);
92325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9233e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski    if (res == VK_SUCCESS && !GetDisables(dev_data)->shader_validation) {
9234b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
9235c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski        const auto new_shader_module = (SPV_SUCCESS == spv_valid ? new shader_module(pCreateInfo) : new shader_module());
9236c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski        dev_data->shaderModuleMap[*pShaderModule] = unique_ptr<shader_module>(new_shader_module);
92375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
92385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return res;
92395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
92405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
92414f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinskistatic bool ValidateAttachmentIndex(layer_data *dev_data, uint32_t attachment, uint32_t attachment_count, const char *type) {
92424f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    bool skip_call = false;
92434f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    if (attachment >= attachment_count && attachment != VK_ATTACHMENT_UNUSED) {
9244df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
9245df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                             __LINE__, VALIDATION_ERROR_00325, "DS",
9246bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             "CreateRenderPass: %s attachment %d must be less than the total number of attachments %d. %s", type,
9247bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             attachment, attachment_count, validation_error_map[VALIDATION_ERROR_00325]);
92484f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    }
92494f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    return skip_call;
92504f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski}
92514f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
9252bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool IsPowerOfTwo(unsigned x) { return x && !(x & (x - 1)); }
9253805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
92544f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinskistatic bool ValidateRenderpassAttachmentUsage(layer_data *dev_data, const VkRenderPassCreateInfo *pCreateInfo) {
92554f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    bool skip_call = false;
92564f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
92574f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
92584f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        if (subpass.pipelineBindPoint != VK_PIPELINE_BIND_POINT_GRAPHICS) {
9259df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
9260df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                 __LINE__, VALIDATION_ERROR_00347, "DS",
92619bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                 "CreateRenderPass: Pipeline bind point for subpass %d must be VK_PIPELINE_BIND_POINT_GRAPHICS. %s",
92629bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                 i, validation_error_map[VALIDATION_ERROR_00347]);
92634f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
92644f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        for (uint32_t j = 0; j < subpass.preserveAttachmentCount; ++j) {
92654f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            uint32_t attachment = subpass.pPreserveAttachments[j];
92664f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) {
9267df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
9268df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                     0, __LINE__, VALIDATION_ERROR_00356, "DS",
92699bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                     "CreateRenderPass:  Preserve attachment (%d) must not be VK_ATTACHMENT_UNUSED. %s", j,
92709bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                     validation_error_map[VALIDATION_ERROR_00356]);
92714f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            } else {
92724f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                skip_call |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Preserve");
92734f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            }
92744f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
92756a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes
9276bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto subpass_performs_resolve =
9277bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            subpass.pResolveAttachments &&
9278bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            std::any_of(subpass.pResolveAttachments, subpass.pResolveAttachments + subpass.colorAttachmentCount,
9279bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        [](VkAttachmentReference ref) { return ref.attachment != VK_ATTACHMENT_UNUSED; });
92806a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes
9281805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes        unsigned sample_count = 0;
9282805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
92834f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
92844f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            uint32_t attachment;
92854f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            if (subpass.pResolveAttachments) {
92864f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                attachment = subpass.pResolveAttachments[j].attachment;
92874f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                skip_call |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Resolve");
92886a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes
92896a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes                if (!skip_call && attachment != VK_ATTACHMENT_UNUSED &&
92906a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes                    pCreateInfo->pAttachments[attachment].samples != VK_SAMPLE_COUNT_1_BIT) {
92916a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
92929bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         __LINE__, VALIDATION_ERROR_00352, "DS",
92936a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes                                         "CreateRenderPass:  Subpass %u requests multisample resolve into attachment %u, "
92949bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         "which must have VK_SAMPLE_COUNT_1_BIT but has %s. %s",
92959bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         i, attachment, string_VkSampleCountFlagBits(pCreateInfo->pAttachments[attachment].samples),
92969bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         validation_error_map[VALIDATION_ERROR_00352]);
92976a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes                }
92984f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            }
92994f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            attachment = subpass.pColorAttachments[j].attachment;
93004f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            skip_call |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Color");
93016a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes
9302805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes            if (!skip_call && attachment != VK_ATTACHMENT_UNUSED) {
9303805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes                sample_count |= (unsigned)pCreateInfo->pAttachments[attachment].samples;
9304805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
9305bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (subpass_performs_resolve && pCreateInfo->pAttachments[attachment].samples == VK_SAMPLE_COUNT_1_BIT) {
9306dc7c45f01ae5690f7c969b4760463c1a6bac52d5Chris Forbes                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
93079bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         __LINE__, VALIDATION_ERROR_00351, "DS",
9308dc7c45f01ae5690f7c969b4760463c1a6bac52d5Chris Forbes                                         "CreateRenderPass:  Subpass %u requests multisample resolve from attachment %u "
93099bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         "which has VK_SAMPLE_COUNT_1_BIT. %s",
93109bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         i, attachment, validation_error_map[VALIDATION_ERROR_00351]);
9311dc7c45f01ae5690f7c969b4760463c1a6bac52d5Chris Forbes                }
93126a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes            }
93134f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
9314dc7c45f01ae5690f7c969b4760463c1a6bac52d5Chris Forbes
93154f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
93164f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            uint32_t attachment = subpass.pDepthStencilAttachment->attachment;
93174f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            skip_call |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Depth stencil");
9318805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
9319805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes            if (!skip_call && attachment != VK_ATTACHMENT_UNUSED) {
9320805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes                sample_count |= (unsigned)pCreateInfo->pAttachments[attachment].samples;
9321805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes            }
93224f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
9323dc7c45f01ae5690f7c969b4760463c1a6bac52d5Chris Forbes
93244f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
93254f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            uint32_t attachment = subpass.pInputAttachments[j].attachment;
93264f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            skip_call |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Input");
93274f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
9328805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
9329805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes        if (sample_count && !IsPowerOfTwo(sample_count)) {
93309bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
9331cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 VALIDATION_ERROR_00337, "DS",
9332cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "CreateRenderPass:  Subpass %u attempts to render to "
9333cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                 "attachments with inconsistent sample counts. %s",
93349bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                 i, validation_error_map[VALIDATION_ERROR_00337]);
9335805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes        }
93364f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    }
93374f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    return skip_call;
93384f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski}
93394f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
93405245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbesstatic void MarkAttachmentFirstUse(RENDER_PASS_STATE *render_pass,
93415245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                                   uint32_t index,
93425245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                                   bool is_read) {
93435245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes    if (index == VK_ATTACHMENT_UNUSED)
93445245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes        return;
93455245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes
93465245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes    if (!render_pass->attachment_first_read.count(index))
93475245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes        render_pass->attachment_first_read[index] = is_read;
93485245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes}
93495245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes
935089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
93514f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                                                const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) {
9352e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
935356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
93544f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
93554f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    std::unique_lock<std::mutex> lock(global_lock);
93564f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    // TODO: As part of wrapping up the mem_tracker/core_validation merge the following routine should be consolidated with
93574f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    //       ValidateLayouts.
93584f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    skip_call |= ValidateRenderpassAttachmentUsage(dev_data, pCreateInfo);
9359208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->dependencyCount; ++i) {
9360208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip_call |= ValidateStageMaskGsTsEnables(dev_data, pCreateInfo->pDependencies[i].srcStageMask, "vkCreateRenderPass()",
9361208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                                                  VALIDATION_ERROR_00368, VALIDATION_ERROR_00370);
9362208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip_call |= ValidateStageMaskGsTsEnables(dev_data, pCreateInfo->pDependencies[i].dstStageMask, "vkCreateRenderPass()",
9363208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                                                  VALIDATION_ERROR_00369, VALIDATION_ERROR_00371);
9364208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    }
9365ab38df28c5ae1816c5fa33c0c7840c6950e83f0dChris Forbes    if (!skip_call) {
9366ab38df28c5ae1816c5fa33c0c7840c6950e83f0dChris Forbes        skip_call |= ValidateLayouts(dev_data, device, pCreateInfo);
9367ab38df28c5ae1816c5fa33c0c7840c6950e83f0dChris Forbes    }
9368ff6101de02d1677fb54962e2ff57875e76898e26Chris Forbes    lock.unlock();
93694f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
93704f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    if (skip_call) {
93714f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        return VK_ERROR_VALIDATION_FAILED_EXT;
93724f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    }
93734f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
93744a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateRenderPass(device, pCreateInfo, pAllocator, pRenderPass);
9375ff6101de02d1677fb54962e2ff57875e76898e26Chris Forbes
93765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
93774f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        lock.lock();
93784f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
93794f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        std::vector<bool> has_self_dependency(pCreateInfo->subpassCount);
93804f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        std::vector<DAGNode> subpass_to_node(pCreateInfo->subpassCount);
93814f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        skip_call |= CreatePassDAG(dev_data, device, pCreateInfo, subpass_to_node, has_self_dependency);
93824f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
9383127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis        auto render_pass = unique_ptr<RENDER_PASS_STATE>(new RENDER_PASS_STATE(pCreateInfo));
938498cddf7090b5d5dcc382045867753ef703d1c3d3Chris Forbes        render_pass->renderPass = *pRenderPass;
9385cf2686cdbb12af8a29ca598c126b5e37215f0ef7Chris Forbes        render_pass->hasSelfDependency = has_self_dependency;
9386cf2686cdbb12af8a29ca598c126b5e37215f0ef7Chris Forbes        render_pass->subpassToNode = subpass_to_node;
9387db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes
938887e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis        for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
938987e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis            const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
939087e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis            for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
93915245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                MarkAttachmentFirstUse(render_pass.get(), subpass.pColorAttachments[j].attachment, false);
93929cde292b1c19c643b7c13018d9834cccfe6ef7eaChris Forbes
93935245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                // resolve attachments are considered to be written
93945245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                if (subpass.pResolveAttachments) {
93955245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                    MarkAttachmentFirstUse(render_pass.get(), subpass.pResolveAttachments[j].attachment, false);
93969cde292b1c19c643b7c13018d9834cccfe6ef7eaChris Forbes                }
939787e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis            }
93985245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes            if (subpass.pDepthStencilAttachment) {
93995245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                MarkAttachmentFirstUse(render_pass.get(), subpass.pDepthStencilAttachment->attachment, false);
940087e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis            }
9401a5ce96d7c88653668a2b33a6b72bd3cb16d73f48Michael Lentine            for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
94025245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                MarkAttachmentFirstUse(render_pass.get(), subpass.pInputAttachments[j].attachment, true);
9403a5ce96d7c88653668a2b33a6b72bd3cb16d73f48Michael Lentine            }
940487e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis        }
9405db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes
9406fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes        dev_data->renderPassMap[*pRenderPass] = std::move(render_pass);
94075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
94085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
94095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
94104f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
94119bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardtstatic bool validatePrimaryCommandBuffer(const layer_data *dev_data, const GLOBAL_CB_NODE *pCB, const std::string &cmd_name,
94129bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         UNIQUE_VALIDATION_ERROR_CODE error_code) {
9413e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
94145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
9415df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9416df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                             reinterpret_cast<uint64_t>(pCB->commandBuffer), __LINE__, error_code, "DS",
9417df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                             "Cannot execute command %s on a secondary command buffer. %s", cmd_name.c_str(),
94189bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                             validation_error_map[error_code]);
94195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
94205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
94215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
94225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
94238860b85a52096f9f9b28616bc37feed505497a54Chris Forbesstatic bool VerifyRenderAreaBounds(const layer_data *dev_data, const VkRenderPassBeginInfo *pRenderPassBegin) {
9424885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine    bool skip_call = false;
9425c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    const safe_VkFramebufferCreateInfo *pFramebufferInfo =
94269a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        &GetFramebufferState(dev_data, pRenderPassBegin->framebuffer)->createInfo;
9427885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine    if (pRenderPassBegin->renderArea.offset.x < 0 ||
9428885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine        (pRenderPassBegin->renderArea.offset.x + pRenderPassBegin->renderArea.extent.width) > pFramebufferInfo->width ||
9429885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine        pRenderPassBegin->renderArea.offset.y < 0 ||
9430885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine        (pRenderPassBegin->renderArea.offset.y + pRenderPassBegin->renderArea.extent.height) > pFramebufferInfo->height) {
9431885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine        skip_call |= static_cast<bool>(log_msg(
9432df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
9433885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            DRAWSTATE_INVALID_RENDER_AREA, "CORE",
9434885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            "Cannot execute a render pass with renderArea not within the bound of the "
9435885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            "framebuffer. RenderArea: x %d, y %d, width %d, height %d. Framebuffer: width %d, "
9436885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            "height %d.",
9437885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            pRenderPassBegin->renderArea.offset.x, pRenderPassBegin->renderArea.offset.y, pRenderPassBegin->renderArea.extent.width,
9438885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            pRenderPassBegin->renderArea.extent.height, pFramebufferInfo->width, pFramebufferInfo->height));
9439885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine    }
9440885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine    return skip_call;
9441885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine}
9442885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine
94431a65650f856376768d7b03ea2d080aaff87cacfdMark 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
94441a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski// [load|store]Op flag must be checked
94451a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski// TODO: The memory valid flag in DEVICE_MEM_INFO should probably be split to track the validity of stencil memory separately.
9446cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskitemplate <typename T>
9447cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskistatic bool FormatSpecificLoadAndStoreOpSettings(VkFormat format, T color_depth_op, T stencil_op, T op) {
9448a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski    if (color_depth_op != op && stencil_op != op) {
9449a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski        return false;
9450a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski    }
94511a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski    bool check_color_depth_load_op = !vk_format_is_stencil_only(format);
94521a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski    bool check_stencil_load_op = vk_format_is_depth_and_stencil(format) || !check_color_depth_load_op;
9453a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski
9454a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski    return (((check_color_depth_load_op == true) && (color_depth_op == op)) ||
9455a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski            ((check_stencil_load_op == true) && (stencil_op == op)));
94561a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski}
94571a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski
9458bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
9459bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              VkSubpassContents contents) {
946083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
946156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
9462b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
94639a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *cb_node = GetCBNode(dev_data, commandBuffer);
94649a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto render_pass_state = pRenderPassBegin ? GetRenderPassState(dev_data, pRenderPassBegin->renderPass) : nullptr;
94659a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto framebuffer = pRenderPassBegin ? GetFramebufferState(dev_data, pRenderPassBegin->framebuffer) : nullptr;
9466f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis    if (cb_node) {
9467308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski        if (render_pass_state) {
9468cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            uint32_t clear_op_size = 0;  // Make sure pClearValues is at least as large as last LOAD_OP_CLEAR
9469f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->activeFramebuffer = pRenderPassBegin->framebuffer;
9470308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski            for (uint32_t i = 0; i < render_pass_state->createInfo.attachmentCount; ++i) {
9471f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes                MT_FB_ATTACHMENT_INFO &fb_info = framebuffer->attachments[i];
9472308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski                auto pAttachment = &render_pass_state->createInfo.pAttachments[i];
9473bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->loadOp, pAttachment->stencilLoadOp,
94741a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski                                                         VK_ATTACHMENT_LOAD_OP_CLEAR)) {
947592bc0680357019834b7529148ab6d73353ce02c7Mark Lobodzinski                    clear_op_size = static_cast<uint32_t>(i) + 1;
947616387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    std::function<bool()> function = [=]() {
94779a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        SetImageMemoryValid(dev_data, GetImageState(dev_data, fb_info.image), true);
947816387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                        return false;
947916387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    };
9480f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                    cb_node->validate_functions.push_back(function);
9481db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes                } else if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->loadOp,
9482bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                pAttachment->stencilLoadOp, VK_ATTACHMENT_LOAD_OP_DONT_CARE)) {
948316387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    std::function<bool()> function = [=]() {
94849a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        SetImageMemoryValid(dev_data, GetImageState(dev_data, fb_info.image), false);
948516387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                        return false;
948616387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    };
9487f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                    cb_node->validate_functions.push_back(function);
9488db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes                } else if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->loadOp,
9489bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                pAttachment->stencilLoadOp, VK_ATTACHMENT_LOAD_OP_LOAD)) {
949016387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    std::function<bool()> function = [=]() {
94919a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        return ValidateImageMemoryIsValid(dev_data, GetImageState(dev_data, fb_info.image),
9492f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis                                                          "vkCmdBeginRenderPass()");
949316387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    };
9494f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                    cb_node->validate_functions.push_back(function);
949516387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                }
9496308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski                if (render_pass_state->attachment_first_read[i]) {
949716387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    std::function<bool()> function = [=]() {
94989a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        return ValidateImageMemoryIsValid(dev_data, GetImageState(dev_data, fb_info.image),
9499f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis                                                          "vkCmdBeginRenderPass()");
950016387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    };
9501f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                    cb_node->validate_functions.push_back(function);
95025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
95035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
95046de3c6ffa0819ee37cd5cecee918b062145e2ff1Tobin Ehlis            if (clear_op_size > pRenderPassBegin->clearValueCount) {
9505369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                skip_call |= log_msg(
9506369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
9507308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski                    reinterpret_cast<uint64_t &>(render_pass_state->renderPass), __LINE__, VALIDATION_ERROR_00442, "DS",
9508bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "In vkCmdBeginRenderPass() the VkRenderPassBeginInfo struct has a clearValueCount of %u but there must "
9509bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "be at least %u entries in pClearValues array to account for the highest index attachment in renderPass "
9510cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "0x%" PRIx64
9511cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    " that uses VK_ATTACHMENT_LOAD_OP_CLEAR is %u. Note that the pClearValues array "
9512bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "is indexed by attachment number so even if some pClearValues entries between 0 and %u correspond to "
9513bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "attachments that aren't cleared they will be ignored. %s",
9514308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski                    pRenderPassBegin->clearValueCount, clear_op_size, reinterpret_cast<uint64_t &>(render_pass_state->renderPass),
95155504d0369cbc97ad7c221eddbad439bfb83e3fb6Mark Lobodzinski                    clear_op_size, clear_op_size - 1, validation_error_map[VALIDATION_ERROR_00442]);
9516369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan            }
9517369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan            if (clear_op_size < pRenderPassBegin->clearValueCount) {
9518369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                skip_call |= log_msg(
9519369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                    dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
9520308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski                    reinterpret_cast<uint64_t &>(render_pass_state->renderPass), __LINE__,
9521308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski                    DRAWSTATE_RENDERPASS_TOO_MANY_CLEAR_VALUES, "DS",
9522369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                    "In vkCmdBeginRenderPass() the VkRenderPassBeginInfo struct has a clearValueCount of %u but only first %u "
95237bab3d8f0599701f6e26a2d76314588486ae99c9Mark Lobodzinski                    "entries in pClearValues array are used. The highest index of any attachment in renderPass 0x%" PRIx64
9524369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                    " that uses VK_ATTACHMENT_LOAD_OP_CLEAR is %u - other pClearValues are ignored.",
9525308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski                    pRenderPassBegin->clearValueCount, clear_op_size, reinterpret_cast<uint64_t &>(render_pass_state->renderPass),
95267bab3d8f0599701f6e26a2d76314588486ae99c9Mark Lobodzinski                    clear_op_size - 1);
95273d71bca42a843966040d6ada9c029e0ec9f35ca6Tobin Ehlis            }
952883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= VerifyRenderAreaBounds(dev_data, pRenderPassBegin);
952955867dbad6ae423b3bd78c15f6771031a710b5adMark Lobodzinski            skip_call |= VerifyFramebufferAndRenderPassLayouts(dev_data, cb_node, pRenderPassBegin,
95309a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                                                               GetFramebufferState(dev_data, pRenderPassBegin->framebuffer));
9531ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen            skip_call |= insideRenderPass(dev_data, cb_node, "vkCmdBeginRenderPass()", VALIDATION_ERROR_00440);
9532308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski            skip_call |= ValidateDependencies(dev_data, framebuffer, render_pass_state);
95339bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt            skip_call |= validatePrimaryCommandBuffer(dev_data, cb_node, "vkCmdBeginRenderPass", VALIDATION_ERROR_00441);
9534baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt            skip_call |=
9535baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                ValidateCmdQueueFlags(dev_data, cb_node, "vkCmdBeginRenderPass()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_00439);
953629f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis            skip_call |= ValidateCmd(dev_data, cb_node, CMD_BEGINRENDERPASS, "vkCmdBeginRenderPass()");
95371ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis            UpdateCmdBufferLastCmd(cb_node, CMD_BEGINRENDERPASS);
9538308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski            cb_node->activeRenderPass = render_pass_state;
95395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // This is a shallow copy as that is all that is needed for now
9540f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->activeRenderPassBeginInfo = *pRenderPassBegin;
9541f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->activeSubpass = 0;
9542f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->activeSubpassContents = contents;
9543f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->framebuffers.insert(pRenderPassBegin->framebuffer);
9544883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis            // Connect this framebuffer and its children to this cmdBuffer
9545883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis            AddFramebufferBinding(dev_data, cb_node, framebuffer);
9546ea0f86230ff5c52f805ac831a1ed5a92bd123368Chris Forbes            // transition attachments to the correct layouts for the first subpass
954755867dbad6ae423b3bd78c15f6771031a710b5adMark Lobodzinski            TransitionSubpassLayouts(dev_data, cb_node, &cb_node->activeRenderPassBeginInfo, cb_node->activeSubpass, framebuffer);
95485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
95495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9550b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
955183b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (!skip_call) {
95524a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdBeginRenderPass(commandBuffer, pRenderPassBegin, contents);
95535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
95545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
95555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
955689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents) {
955783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
955856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
9559b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
95609a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
95615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
95629bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt        skip_call |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdNextSubpass", VALIDATION_ERROR_00459);
9563baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip_call |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdNextSubpass()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_00457);
956429f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_NEXTSUBPASS, "vkCmdNextSubpass()");
95651ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_NEXTSUBPASS);
9566ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen        skip_call |= outsideRenderPass(dev_data, pCB, "vkCmdNextSubpass()", VALIDATION_ERROR_00458);
956780281691386b37385846f21b38e8c9d4b12cc74eChris Forbes
9568fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes        auto subpassCount = pCB->activeRenderPass->createInfo.subpassCount;
956980281691386b37385846f21b38e8c9d4b12cc74eChris Forbes        if (pCB->activeSubpass == subpassCount - 1) {
95709bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt            skip_call |= log_msg(
95719bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
95729bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                reinterpret_cast<uint64_t>(commandBuffer), __LINE__, VALIDATION_ERROR_00453, "DS",
95739bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                "vkCmdNextSubpass(): Attempted to advance beyond final subpass. %s", validation_error_map[VALIDATION_ERROR_00453]);
957480281691386b37385846f21b38e8c9d4b12cc74eChris Forbes        }
95755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9576b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
957796ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes
9578cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return;
957996ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes
95804a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.CmdNextSubpass(commandBuffer, contents);
958196ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes
958296ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes    if (pCB) {
9583bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        lock.lock();
9584bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pCB->activeSubpass++;
9585bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pCB->activeSubpassContents = contents;
958655867dbad6ae423b3bd78c15f6771031a710b5adMark Lobodzinski        TransitionSubpassLayouts(dev_data, pCB, &pCB->activeRenderPassBeginInfo, pCB->activeSubpass,
95879a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                                 GetFramebufferState(dev_data, pCB->activeRenderPassBeginInfo.framebuffer));
958896ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes    }
95895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
95905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
959189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdEndRenderPass(VkCommandBuffer commandBuffer) {
959283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
959356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
9594b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
95959a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pCB = GetCBNode(dev_data, commandBuffer);
959655867dbad6ae423b3bd78c15f6771031a710b5adMark Lobodzinski    FRAMEBUFFER_STATE *framebuffer = NULL;
959758c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes    if (pCB) {
9598127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis        RENDER_PASS_STATE *rp_state = pCB->activeRenderPass;
95999a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        framebuffer = GetFramebufferState(dev_data, pCB->activeFramebuffer);
9600127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis        if (rp_state) {
9601127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis            if (pCB->activeSubpass != rp_state->createInfo.subpassCount - 1) {
96029bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                skip_call |= log_msg(
96039bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
96049bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                    reinterpret_cast<uint64_t>(commandBuffer), __LINE__, VALIDATION_ERROR_00460, "DS",
96059bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                    "vkCmdEndRenderPass(): Called before reaching final subpass. %s", validation_error_map[VALIDATION_ERROR_00460]);
960602a3382f28fc7c6ec6018165be88aa6fc4f05c9eChris Forbes            }
960702a3382f28fc7c6ec6018165be88aa6fc4f05c9eChris Forbes
9608127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis            for (size_t i = 0; i < rp_state->createInfo.attachmentCount; ++i) {
9609e3ad4b1284408353cc56a04951c1df1f35a636ceChris Forbes                MT_FB_ATTACHMENT_INFO &fb_info = framebuffer->attachments[i];
9610127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                auto pAttachment = &rp_state->createInfo.pAttachments[i];
9611bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->storeOp, pAttachment->stencilStoreOp,
9612bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                         VK_ATTACHMENT_STORE_OP_STORE)) {
961358c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    std::function<bool()> function = [=]() {
96149a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        SetImageMemoryValid(dev_data, GetImageState(dev_data, fb_info.image), true);
961558c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                        return false;
961658c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    };
961758c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    pCB->validate_functions.push_back(function);
9618db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes                } else if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->storeOp,
9619bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                pAttachment->stencilStoreOp, VK_ATTACHMENT_STORE_OP_DONT_CARE)) {
962058c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    std::function<bool()> function = [=]() {
96219a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        SetImageMemoryValid(dev_data, GetImageState(dev_data, fb_info.image), false);
962258c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                        return false;
962358c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    };
962458c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    pCB->validate_functions.push_back(function);
96255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
96265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
96275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
9628ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen        skip_call |= outsideRenderPass(dev_data, pCB, "vkCmdEndRenderpass()", VALIDATION_ERROR_00464);
96299bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt        skip_call |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdEndRenderPass", VALIDATION_ERROR_00465);
9630baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip_call |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdEndRenderPass()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_00463);
963129f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_ENDRENDERPASS, "vkCmdEndRenderPass()");
96321ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_ENDRENDERPASS);
96330e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes    }
96340e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes    lock.unlock();
96350e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes
9636cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return;
96370e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes
96384a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.CmdEndRenderPass(commandBuffer);
96390e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes
96400e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes    if (pCB) {
96410e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes        lock.lock();
964255867dbad6ae423b3bd78c15f6771031a710b5adMark Lobodzinski        TransitionFinalSubpassLayouts(dev_data, pCB, &pCB->activeRenderPassBeginInfo, framebuffer);
964358c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes        pCB->activeRenderPass = nullptr;
964458c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes        pCB->activeSubpass = 0;
964558c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes        pCB->activeFramebuffer = VK_NULL_HANDLE;
96465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
96475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
96485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9649a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlisstatic bool logInvalidAttachmentMessage(layer_data *dev_data, VkCommandBuffer secondaryBuffer, uint32_t primaryAttach,
9650a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                        uint32_t secondaryAttach, const char *msg) {
9651df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski    return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9652df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                   reinterpret_cast<uint64_t>(secondaryBuffer), __LINE__, VALIDATION_ERROR_02059, "DS",
9653df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                   "vkCmdExecuteCommands() called w/ invalid Secondary Cmd Buffer 0x%" PRIx64
9654df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                   " which has a render pass "
9655df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                   "that is not compatible with the Primary Cmd Buffer current render pass. "
9656df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                   "Attachment %u is not compatible with %u: %s. %s",
96579bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                   reinterpret_cast<uint64_t &>(secondaryBuffer), primaryAttach, secondaryAttach, msg,
96589bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                   validation_error_map[VALIDATION_ERROR_02059]);
96595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
96605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9661a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlisstatic bool validateAttachmentCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer,
9662a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                            VkRenderPassCreateInfo const *primaryPassCI, uint32_t primaryAttach,
9663a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                            VkCommandBuffer secondaryBuffer, VkRenderPassCreateInfo const *secondaryPassCI,
9664e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                                            uint32_t secondaryAttach, bool is_multi) {
96655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool skip_call = false;
9666a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (primaryPassCI->attachmentCount <= primaryAttach) {
96675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        primaryAttach = VK_ATTACHMENT_UNUSED;
96685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9669a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (secondaryPassCI->attachmentCount <= secondaryAttach) {
96705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        secondaryAttach = VK_ATTACHMENT_UNUSED;
96715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
96725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (primaryAttach == VK_ATTACHMENT_UNUSED && secondaryAttach == VK_ATTACHMENT_UNUSED) {
96735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return skip_call;
96745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
96755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (primaryAttach == VK_ATTACHMENT_UNUSED) {
9676a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach,
9677a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                                 "The first is unused while the second is not.");
96785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return skip_call;
96795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
96805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (secondaryAttach == VK_ATTACHMENT_UNUSED) {
9681a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach,
9682a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                                 "The second is unused while the first is not.");
96835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return skip_call;
96845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9685a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (primaryPassCI->pAttachments[primaryAttach].format != secondaryPassCI->pAttachments[secondaryAttach].format) {
9686a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        skip_call |=
9687a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis            logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach, "They have different formats.");
96885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9689a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (primaryPassCI->pAttachments[primaryAttach].samples != secondaryPassCI->pAttachments[secondaryAttach].samples) {
9690a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        skip_call |=
9691a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis            logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach, "They have different samples.");
96925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9693a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (is_multi && primaryPassCI->pAttachments[primaryAttach].flags != secondaryPassCI->pAttachments[secondaryAttach].flags) {
9694a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        skip_call |=
9695a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis            logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach, "They have different flags.");
96965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
96975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
96985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
96995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9700a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlisstatic bool validateSubpassCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer,
9701a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                         VkRenderPassCreateInfo const *primaryPassCI, VkCommandBuffer secondaryBuffer,
9702a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                         VkRenderPassCreateInfo const *secondaryPassCI, const int subpass, bool is_multi) {
97035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool skip_call = false;
9704a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    const VkSubpassDescription &primary_desc = primaryPassCI->pSubpasses[subpass];
9705a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    const VkSubpassDescription &secondary_desc = secondaryPassCI->pSubpasses[subpass];
97065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t maxInputAttachmentCount = std::max(primary_desc.inputAttachmentCount, secondary_desc.inputAttachmentCount);
97075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < maxInputAttachmentCount; ++i) {
97085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primary_input_attach = VK_ATTACHMENT_UNUSED, secondary_input_attach = VK_ATTACHMENT_UNUSED;
97095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < primary_desc.inputAttachmentCount) {
97105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            primary_input_attach = primary_desc.pInputAttachments[i].attachment;
97115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
97125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < secondary_desc.inputAttachmentCount) {
97135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            secondary_input_attach = secondary_desc.pInputAttachments[i].attachment;
97145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
9715a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPassCI, primary_input_attach, secondaryBuffer,
9716a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                                     secondaryPassCI, secondary_input_attach, is_multi);
97175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
97185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t maxColorAttachmentCount = std::max(primary_desc.colorAttachmentCount, secondary_desc.colorAttachmentCount);
97195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < maxColorAttachmentCount; ++i) {
97205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primary_color_attach = VK_ATTACHMENT_UNUSED, secondary_color_attach = VK_ATTACHMENT_UNUSED;
97215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < primary_desc.colorAttachmentCount) {
97225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            primary_color_attach = primary_desc.pColorAttachments[i].attachment;
97235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
97245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < secondary_desc.colorAttachmentCount) {
97255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            secondary_color_attach = secondary_desc.pColorAttachments[i].attachment;
97265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
9727a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPassCI, primary_color_attach, secondaryBuffer,
9728a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                                     secondaryPassCI, secondary_color_attach, is_multi);
97295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primary_resolve_attach = VK_ATTACHMENT_UNUSED, secondary_resolve_attach = VK_ATTACHMENT_UNUSED;
97305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < primary_desc.colorAttachmentCount && primary_desc.pResolveAttachments) {
97315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            primary_resolve_attach = primary_desc.pResolveAttachments[i].attachment;
97325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
97335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < secondary_desc.colorAttachmentCount && secondary_desc.pResolveAttachments) {
97345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            secondary_resolve_attach = secondary_desc.pResolveAttachments[i].attachment;
97355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
9736a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPassCI, primary_resolve_attach,
9737a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                                     secondaryBuffer, secondaryPassCI, secondary_resolve_attach, is_multi);
97385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
97395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t primary_depthstencil_attach = VK_ATTACHMENT_UNUSED, secondary_depthstencil_attach = VK_ATTACHMENT_UNUSED;
97405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (primary_desc.pDepthStencilAttachment) {
97415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        primary_depthstencil_attach = primary_desc.pDepthStencilAttachment[0].attachment;
97425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
97435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (secondary_desc.pDepthStencilAttachment) {
97445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        secondary_depthstencil_attach = secondary_desc.pDepthStencilAttachment[0].attachment;
97455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9746a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPassCI, primary_depthstencil_attach,
9747a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                                 secondaryBuffer, secondaryPassCI, secondary_depthstencil_attach, is_multi);
97485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
97495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
97505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9751a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis// Verify that given renderPass CreateInfo for primary and secondary command buffers are compatible.
9752a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis//  This function deals directly with the CreateInfo, there are overloaded versions below that can take the renderPass handle and
9753a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis//  will then feed into this function
9754a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlisstatic bool validateRenderPassCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer,
9755a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                            VkRenderPassCreateInfo const *primaryPassCI, VkCommandBuffer secondaryBuffer,
9756a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                            VkRenderPassCreateInfo const *secondaryPassCI) {
97575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool skip_call = false;
9758a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis
9759a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (primaryPassCI->subpassCount != secondaryPassCI->subpassCount) {
9760df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9761df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                             reinterpret_cast<uint64_t>(primaryBuffer), __LINE__, DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
9762a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                             "vkCmdExecuteCommands() called w/ invalid secondary Cmd Buffer 0x%" PRIx64
9763a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                             " that has a subpassCount of %u that is incompatible with the primary Cmd Buffer 0x%" PRIx64
9764a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                             " that has a subpassCount of %u.",
9765a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                             reinterpret_cast<uint64_t &>(secondaryBuffer), secondaryPassCI->subpassCount,
9766a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                             reinterpret_cast<uint64_t &>(primaryBuffer), primaryPassCI->subpassCount);
9767a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    } else {
9768a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        for (uint32_t i = 0; i < primaryPassCI->subpassCount; ++i) {
9769a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis            skip_call |= validateSubpassCompatibility(dev_data, primaryBuffer, primaryPassCI, secondaryBuffer, secondaryPassCI, i,
9770a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                                      primaryPassCI->subpassCount > 1);
9771a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        }
97725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
97735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
97745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
97755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9776e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool validateFramebuffer(layer_data *dev_data, VkCommandBuffer primaryBuffer, const GLOBAL_CB_NODE *pCB,
9777e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                                VkCommandBuffer secondaryBuffer, const GLOBAL_CB_NODE *pSubCB) {
97785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool skip_call = false;
97795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (!pSubCB->beginInfo.pInheritanceInfo) {
97805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return skip_call;
97815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9782c5b97dda856ff837638b3ebb7e231d5507c495a3Chris Forbes    VkFramebuffer primary_fb = pCB->activeFramebuffer;
97835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkFramebuffer secondary_fb = pSubCB->beginInfo.pInheritanceInfo->framebuffer;
97845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (secondary_fb != VK_NULL_HANDLE) {
97855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (primary_fb != secondary_fb) {
97869bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt            skip_call |= log_msg(
9787df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9788df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                reinterpret_cast<uint64_t>(primaryBuffer), __LINE__, VALIDATION_ERROR_02060, "DS",
97899bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                "vkCmdExecuteCommands() called w/ invalid secondary command buffer 0x%" PRIx64 " which has a framebuffer 0x%" PRIx64
97909bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                " that is not the same as the primary command buffer's current active framebuffer 0x%" PRIx64 ". %s",
97919bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                reinterpret_cast<uint64_t &>(secondaryBuffer), reinterpret_cast<uint64_t &>(secondary_fb),
97929bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                reinterpret_cast<uint64_t &>(primary_fb), validation_error_map[VALIDATION_ERROR_02060]);
97935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
97949a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto fb = GetFramebufferState(dev_data, secondary_fb);
9795e3ad4b1284408353cc56a04951c1df1f35a636ceChris Forbes        if (!fb) {
9796df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip_call |=
9797df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9798df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        reinterpret_cast<uint64_t>(primaryBuffer), __LINE__, DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
9799df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        "vkCmdExecuteCommands() called w/ invalid Cmd Buffer 0x%p "
9800df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        "which has invalid framebuffer 0x%" PRIx64 ".",
9801df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        (void *)secondaryBuffer, (uint64_t)(secondary_fb));
98025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return skip_call;
98035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
98049a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto cb_renderpass = GetRenderPassState(dev_data, pSubCB->beginInfo.pInheritanceInfo->renderPass);
9805a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        if (cb_renderpass->renderPass != fb->createInfo.renderPass) {
9806a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis            skip_call |= validateRenderPassCompatibility(dev_data, secondaryBuffer, fb->renderPassCreateInfo.ptr(), secondaryBuffer,
9807fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes                                                         cb_renderpass->createInfo.ptr());
9808a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        }
98095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
98105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return skip_call;
98115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
98125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9813e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool validateSecondaryCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB, GLOBAL_CB_NODE *pSubCB) {
981483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
98155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_set<int> activeTypes;
98165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto queryObject : pCB->activeQueries) {
98175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto queryPoolData = dev_data->queryPoolMap.find(queryObject.pool);
98185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (queryPoolData != dev_data->queryPoolMap.end()) {
98195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (queryPoolData->second.createInfo.queryType == VK_QUERY_TYPE_PIPELINE_STATISTICS &&
98205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pSubCB->beginInfo.pInheritanceInfo) {
98215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                VkQueryPipelineStatisticFlags cmdBufStatistics = pSubCB->beginInfo.pInheritanceInfo->pipelineStatistics;
98225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if ((cmdBufStatistics & queryPoolData->second.createInfo.pipelineStatistics) != cmdBufStatistics) {
9823df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
9824df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                         VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9825df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                         reinterpret_cast<uint64_t>(pCB->commandBuffer), __LINE__, VALIDATION_ERROR_02065, "DS",
9826cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         "vkCmdExecuteCommands() called w/ invalid Cmd Buffer 0x%p "
9827cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         "which has invalid active query pool 0x%" PRIx64
9828cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         ". Pipeline statistics is being queried so the command "
9829cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         "buffer must have all bits set on the queryPool. %s",
9830cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         pCB->commandBuffer, reinterpret_cast<const uint64_t &>(queryPoolData->first),
9831cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         validation_error_map[VALIDATION_ERROR_02065]);
98325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
98335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
98345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            activeTypes.insert(queryPoolData->second.createInfo.queryType);
98355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
98365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
98375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto queryObject : pSubCB->startedQueries) {
98385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto queryPoolData = dev_data->queryPoolMap.find(queryObject.pool);
98395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (queryPoolData != dev_data->queryPoolMap.end() && activeTypes.count(queryPoolData->second.createInfo.queryType)) {
9840df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip_call |=
9841df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9842df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        reinterpret_cast<uint64_t>(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
9843df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        "vkCmdExecuteCommands() called w/ invalid Cmd Buffer 0x%p "
9844df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        "which has invalid active query pool 0x%" PRIx64
9845df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        "of type %d but a query of that type has been started on "
9846df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        "secondary Cmd Buffer 0x%p.",
9847df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        pCB->commandBuffer, reinterpret_cast<const uint64_t &>(queryPoolData->first),
9848df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        queryPoolData->second.createInfo.queryType, pSubCB->commandBuffer);
98495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
98505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
98517bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
98529a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto primary_pool = GetCommandPoolNode(dev_data, pCB->createInfo.commandPool);
98539a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto secondary_pool = GetCommandPoolNode(dev_data, pSubCB->createInfo.commandPool);
98547bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski    if (primary_pool && secondary_pool && (primary_pool->queueFamilyIndex != secondary_pool->queueFamilyIndex)) {
9855226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis        skip_call |=
9856226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9857226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    reinterpret_cast<uint64_t>(pSubCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_QUEUE_FAMILY, "DS",
9858226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    "vkCmdExecuteCommands(): Primary command buffer 0x%p"
9859226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    " created in queue family %d has secondary command buffer 0x%p created in queue family %d.",
9860226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    pCB->commandBuffer, primary_pool->queueFamilyIndex, pSubCB->commandBuffer, secondary_pool->queueFamilyIndex);
98617bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski    }
98627bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
986383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    return skip_call;
98645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
98655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9866bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBuffersCount,
9867bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              const VkCommandBuffer *pCommandBuffers) {
986883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
986956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
9870b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
98719a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
98725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
98735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        GLOBAL_CB_NODE *pSubCB = NULL;
98745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < commandBuffersCount; i++) {
98759a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            pSubCB = GetCBNode(dev_data, pCommandBuffers[i]);
98760a8b955c23012196339f3c10ffedc631ea0f7c58Tobin Ehlis            assert(pSubCB);
98770a8b955c23012196339f3c10ffedc631ea0f7c58Tobin Ehlis            if (VK_COMMAND_BUFFER_LEVEL_PRIMARY == pSubCB->createInfo.level) {
9878df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                skip_call |=
9879df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9880df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            reinterpret_cast<uint64_t>(pCommandBuffers[i]), __LINE__, VALIDATION_ERROR_00153, "DS",
9881df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "vkCmdExecuteCommands() called w/ Primary Cmd Buffer 0x%p in element %u of pCommandBuffers "
9882df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "array. All cmd buffers in pCommandBuffers array must be secondary. %s",
9883df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            pCommandBuffers[i], i, validation_error_map[VALIDATION_ERROR_00153]);
9884cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else if (pCB->activeRenderPass) {  // Secondary CB w/i RenderPass must have *CONTINUE_BIT set
98859a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto secondary_rp_state = GetRenderPassState(dev_data, pSubCB->beginInfo.pInheritanceInfo->renderPass);
98865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (!(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
988783b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |= log_msg(
98885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9889df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        reinterpret_cast<uint64_t>(pCommandBuffers[i]), __LINE__, VALIDATION_ERROR_02057, "DS",
9890414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                        "vkCmdExecuteCommands(): Secondary Command Buffer (0x%p) executed within render pass (0x%" PRIxLEAST64
98914b6738a6adb4e813d66234defee5d18b7c84340dMike Weiblen                        ") must have had vkBeginCommandBuffer() called w/ VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT set. %s",
9892226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        pCommandBuffers[i], (uint64_t)pCB->activeRenderPass->renderPass,
98934b6738a6adb4e813d66234defee5d18b7c84340dMike Weiblen                        validation_error_map[VALIDATION_ERROR_02057]);
98945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                } else {
98955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    // Make sure render pass is compatible with parent command buffer pass if has continue
9896127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                    if (pCB->activeRenderPass->renderPass != secondary_rp_state->renderPass) {
9897fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes                        skip_call |=
9898fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes                            validateRenderPassCompatibility(dev_data, commandBuffer, pCB->activeRenderPass->createInfo.ptr(),
9899127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                                                            pCommandBuffers[i], secondary_rp_state->createInfo.ptr());
9900a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                    }
99011af6125615cd6dd9735d32e2ee8684abeff28d41Tobin Ehlis                    //  If framebuffer for secondary CB is not NULL, then it must match active FB from primaryCB
990283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |= validateFramebuffer(dev_data, commandBuffer, pCB, pCommandBuffers[i], pSubCB);
99035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
99045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                string errorString = "";
99051af6125615cd6dd9735d32e2ee8684abeff28d41Tobin Ehlis                // secondaryCB must have been created w/ RP compatible w/ primaryCB active renderpass
9906127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                if ((pCB->activeRenderPass->renderPass != secondary_rp_state->renderPass) &&
9907fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes                    !verify_renderpass_compatibility(dev_data, pCB->activeRenderPass->createInfo.ptr(),
9908127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                                                     secondary_rp_state->createInfo.ptr(), errorString)) {
990983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |= log_msg(
99105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9911df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        reinterpret_cast<uint64_t>(pCommandBuffers[i]), __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE, "DS",
9912414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                        "vkCmdExecuteCommands(): Secondary Command Buffer (0x%p) w/ render pass (0x%" PRIxLEAST64
9913414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                        ") is incompatible w/ primary command buffer (0x%p) w/ render pass (0x%" PRIxLEAST64 ") due to: %s",
9914226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        pCommandBuffers[i], (uint64_t)pSubCB->beginInfo.pInheritanceInfo->renderPass, commandBuffer,
9915ee691f5c5fa87aac3750454d2bca2cb582e4e817Chris Forbes                        (uint64_t)pCB->activeRenderPass->renderPass, errorString.c_str());
99165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
99175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
99185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // TODO(mlentine): Move more logic into this method
991983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis            skip_call |= validateSecondaryCommandBufferState(dev_data, pCB, pSubCB);
992051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            skip_call |= validateCommandBufferState(dev_data, pSubCB, "vkCmdExecuteCommands()", 0);
99215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Secondary cmdBuffers are considered pending execution starting w/
99225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // being recorded
99235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
99245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (dev_data->globalInFlightCmdBuffers.find(pSubCB->commandBuffer) != dev_data->globalInFlightCmdBuffers.end()) {
9925cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
9926df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                         VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9927df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                         reinterpret_cast<uint64_t>(pCB->commandBuffer), __LINE__, VALIDATION_ERROR_00154, "DS",
9928cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         "Attempt to simultaneously execute command buffer 0x%p"
9929cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         " without VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set! %s",
9930cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         pCB->commandBuffer, validation_error_map[VALIDATION_ERROR_00154]);
99315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
99325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT) {
99335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    // Warn that non-simultaneous secondary cmd buffer renders primary non-simultaneous
993483b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                    skip_call |= log_msg(
99355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9936df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        reinterpret_cast<uint64_t>(pCommandBuffers[i]), __LINE__, DRAWSTATE_INVALID_CB_SIMULTANEOUS_USE, "DS",
9937226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "vkCmdExecuteCommands(): Secondary Command Buffer (0x%p) "
9938226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set and will cause primary command buffer "
9939226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "(0x%p) to be treated as if it does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT "
994083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                        "set, even though it does.",
9941226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        pCommandBuffers[i], pCB->commandBuffer);
99425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    pCB->beginInfo.flags &= ~VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
99435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
99445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
9945f71dd305f197826a61f398bff725267a20ea1d90Chris Forbes            if (!pCB->activeQueries.empty() && !dev_data->enabled_features.inheritedQueries) {
9946cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                skip_call |=
9947cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9948cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            reinterpret_cast<uint64_t>(pCommandBuffers[i]), __LINE__, VALIDATION_ERROR_02062, "DS",
9949cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "vkCmdExecuteCommands(): Secondary Command Buffer "
9950cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "(0x%p) cannot be submitted with a query in "
9951cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "flight and inherited queries not "
9952cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "supported on this device. %s",
9953cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            pCommandBuffers[i], validation_error_map[VALIDATION_ERROR_02062]);
99545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
99558567fecbf563420f5900ade277ca68908aa87259Tobin Ehlis            // Propagate layout transitions to the primary cmd buffer
99568567fecbf563420f5900ade277ca68908aa87259Tobin Ehlis            for (auto ilm_entry : pSubCB->imageLayoutMap) {
995755867dbad6ae423b3bd78c15f6771031a710b5adMark Lobodzinski                SetLayout(dev_data, pCB, ilm_entry.first, ilm_entry.second);
99588567fecbf563420f5900ade277ca68908aa87259Tobin Ehlis            }
99595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pSubCB->primaryCommandBuffer = pCB->commandBuffer;
99605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pCB->secondaryCommandBuffers.insert(pSubCB->commandBuffer);
99615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->globalInFlightCmdBuffers.insert(pSubCB->commandBuffer);
9962d4ee9fdb2def1e9dc70c5627c9103e264471b8ebMichael Lentine            for (auto &function : pSubCB->queryUpdates) {
9963d4ee9fdb2def1e9dc70c5627c9103e264471b8ebMichael Lentine                pCB->queryUpdates.push_back(function);
9964d4ee9fdb2def1e9dc70c5627c9103e264471b8ebMichael Lentine            }
99655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
99669bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt        skip_call |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdExecuteComands", VALIDATION_ERROR_00163);
9967baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip_call |=
9968baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt            ValidateCmdQueueFlags(dev_data, pCB, "vkCmdExecuteComands()",
9969baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                  VK_QUEUE_TRANSFER_BIT | VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, VALIDATION_ERROR_00162);
997029f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip_call |= ValidateCmd(dev_data, pCB, CMD_EXECUTECOMMANDS, "vkCmdExecuteComands()");
99711ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_EXECUTECOMMANDS);
99725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9973b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
9974cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.CmdExecuteCommands(commandBuffer, commandBuffersCount, pCommandBuffers);
99755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
99765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9977bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL MapMemory(VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size, VkFlags flags,
9978bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         void **ppData) {
997956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
99805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9981e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
99825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
9983b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
99849a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
9985cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    if (mem_info) {
9986f541bf53dee6daf82a4c8304354eac599a884d29Tobin Ehlis        // TODO : This could me more fine-grained to track just region that is valid
9987f541bf53dee6daf82a4c8304354eac599a884d29Tobin Ehlis        mem_info->global_valid = true;
9988623548a271287ae55415e45e3c654ee66d4e79ffTobin Ehlis        auto end_offset = (VK_WHOLE_SIZE == size) ? mem_info->alloc_info.allocationSize - 1 : offset + size - 1;
9989c3340a06ecac4d7b9540592cae339f8fc224d0b1Mark Lobodzinski        skip_call |= ValidateMapImageLayouts(dev_data, device, mem_info, offset, end_offset);
9990cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis        // TODO : Do we need to create new "bound_range" for the mapped range?
9991623548a271287ae55415e45e3c654ee66d4e79ffTobin Ehlis        SetMemRangesValid(dev_data, mem_info, offset, end_offset);
9992cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis        if ((dev_data->phys_dev_mem_props.memoryTypes[mem_info->alloc_info.memoryTypeIndex].propertyFlags &
9993b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis             VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) {
99942fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen            skip_call = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
99952fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                (uint64_t)mem, __LINE__, VALIDATION_ERROR_00629, "MEM",
99962fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                "Mapping Memory without VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT set: mem obj 0x%" PRIxLEAST64 ". %s",
99972fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                (uint64_t)mem, validation_error_map[VALIDATION_ERROR_00629]);
99985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
99995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10000f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis    skip_call |= ValidateMapMemRange(dev_data, mem, offset, size);
10001b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
100025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10003e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    if (!skip_call) {
100044a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.MapMemory(device, mem, offset, size, flags, ppData);
100057c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis        if (VK_SUCCESS == result) {
100067c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis            lock.lock();
10007cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis            // TODO : What's the point of this range? See comment on creating new "bound_range" above, which may replace this
100087c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis            storeMemRanges(dev_data, mem, offset, size);
100095f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            initializeAndTrackMemory(dev_data, mem, offset, size, ppData);
100107c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis            lock.unlock();
100117c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis        }
100125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
100135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
100145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
100155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1001689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL UnmapMemory(VkDevice device, VkDeviceMemory mem) {
1001756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
1001883b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
100195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10020b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
100218860b85a52096f9f9b28616bc37feed505497a54Chris Forbes    skip_call |= deleteMemRanges(dev_data, mem);
10022b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
1002383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    if (!skip_call) {
100244a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.UnmapMemory(device, mem);
100255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
100265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
100275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
100288860b85a52096f9f9b28616bc37feed505497a54Chris Forbesstatic bool validateMemoryIsMapped(layer_data *dev_data, const char *funcName, uint32_t memRangeCount,
10029e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                                   const VkMappedMemoryRange *pMemRanges) {
10030c7ee6f2fe100c1aacfaa0872832717c906bb8a4aMark Lobodzinski    bool skip = false;
100315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < memRangeCount; ++i) {
100329a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto mem_info = GetMemObjInfo(dev_data, pMemRanges[i].memory);
1003357fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        if (mem_info) {
10034f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski            if (pMemRanges[i].size == VK_WHOLE_SIZE) {
10035f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                if (mem_info->mem_range.offset > pMemRanges[i].offset) {
10036cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
10037cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)pMemRanges[i].memory, __LINE__,
10038cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    VALIDATION_ERROR_00643, "MEM", "%s: Flush/Invalidate offset (" PRINTF_SIZE_T_SPECIFIER
10039cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                                   ") is less than Memory Object's offset "
10040cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                                   "(" PRINTF_SIZE_T_SPECIFIER "). %s",
10041cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    funcName, static_cast<size_t>(pMemRanges[i].offset),
10042cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                    static_cast<size_t>(mem_info->mem_range.offset), validation_error_map[VALIDATION_ERROR_00643]);
10043f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                }
10044f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski            } else {
10045f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                const uint64_t data_end = (mem_info->mem_range.size == VK_WHOLE_SIZE)
10046f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                              ? mem_info->alloc_info.allocationSize
10047f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                              : (mem_info->mem_range.offset + mem_info->mem_range.size);
10048f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                if ((mem_info->mem_range.offset > pMemRanges[i].offset) ||
10049f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                    (data_end < (pMemRanges[i].offset + pMemRanges[i].size))) {
10050c7ee6f2fe100c1aacfaa0872832717c906bb8a4aMark Lobodzinski                    skip |=
10051f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
10052f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                (uint64_t)pMemRanges[i].memory, __LINE__, VALIDATION_ERROR_00642, "MEM",
10053f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                "%s: Flush/Invalidate size or offset (" PRINTF_SIZE_T_SPECIFIER ", " PRINTF_SIZE_T_SPECIFIER
10054f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                ") exceed the Memory Object's upper-bound "
10055f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                "(" PRINTF_SIZE_T_SPECIFIER "). %s",
10056f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                funcName, static_cast<size_t>(pMemRanges[i].offset + pMemRanges[i].size),
10057f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                static_cast<size_t>(pMemRanges[i].offset), static_cast<size_t>(data_end),
10058f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                validation_error_map[VALIDATION_ERROR_00642]);
10059f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                }
100605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
100615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
100625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10063c7ee6f2fe100c1aacfaa0872832717c906bb8a4aMark Lobodzinski    return skip;
100645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
100655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10066bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinskistatic bool ValidateAndCopyNoncoherentMemoryToDriver(layer_data *dev_data, uint32_t mem_range_count,
10067bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                                     const VkMappedMemoryRange *mem_ranges) {
10068bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski    bool skip = false;
10069bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski    for (uint32_t i = 0; i < mem_range_count; ++i) {
100709a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto mem_info = GetMemObjInfo(dev_data, mem_ranges[i].memory);
1007157fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        if (mem_info) {
100725f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            if (mem_info->shadow_copy) {
100735f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                VkDeviceSize size = (mem_info->mem_range.size != VK_WHOLE_SIZE)
100745f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                        ? mem_info->mem_range.size
10075d8a53ade6b5501256798a8b4ec0bc14f72adc1faTobin Ehlis                                        : (mem_info->alloc_info.allocationSize - mem_info->mem_range.offset);
100765f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                char *data = static_cast<char *>(mem_info->shadow_copy);
100775f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                for (uint64_t j = 0; j < mem_info->shadow_pad_size; ++j) {
100785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    if (data[j] != NoncoherentMemoryFillValue) {
10079bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
10080bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                        VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)mem_ranges[i].memory, __LINE__,
10081bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                        MEMTRACK_INVALID_MAP, "MEM", "Memory underflow was detected on mem obj 0x%" PRIxLEAST64,
10082bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                        (uint64_t)mem_ranges[i].memory);
100835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
100845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
100855f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                for (uint64_t j = (size + mem_info->shadow_pad_size); j < (2 * mem_info->shadow_pad_size + size); ++j) {
100865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    if (data[j] != NoncoherentMemoryFillValue) {
10087bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
10088bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                        VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)mem_ranges[i].memory, __LINE__,
10089bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                        MEMTRACK_INVALID_MAP, "MEM", "Memory overflow was detected on mem obj 0x%" PRIxLEAST64,
10090bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                        (uint64_t)mem_ranges[i].memory);
100915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
100925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
100935f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                memcpy(mem_info->p_driver_data, static_cast<void *>(data + mem_info->shadow_pad_size), (size_t)(size));
100945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
100955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
100965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10097bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski    return skip;
100985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
100995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10100bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinskistatic void CopyNoncoherentMemoryFromDriver(layer_data *dev_data, uint32_t mem_range_count, const VkMappedMemoryRange *mem_ranges) {
10101bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski    for (uint32_t i = 0; i < mem_range_count; ++i) {
101029a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto mem_info = GetMemObjInfo(dev_data, mem_ranges[i].memory);
101035f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski        if (mem_info && mem_info->shadow_copy) {
101045f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            VkDeviceSize size = (mem_info->mem_range.size != VK_WHOLE_SIZE)
101055f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                    ? mem_info->mem_range.size
101065f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                    : (mem_info->alloc_info.allocationSize - mem_ranges[i].offset);
101075f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            char *data = static_cast<char *>(mem_info->shadow_copy);
101085f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            memcpy(data + mem_info->shadow_pad_size, mem_info->p_driver_data, (size_t)(size));
101099e21e56fc23ade48efd3752d2e2729895eb90349Mark Lobodzinski        }
101109e21e56fc23ade48efd3752d2e2729895eb90349Mark Lobodzinski    }
101119e21e56fc23ade48efd3752d2e2729895eb90349Mark Lobodzinski}
101129e21e56fc23ade48efd3752d2e2729895eb90349Mark Lobodzinski
10113ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinskistatic bool ValidateMappedMemoryRangeDeviceLimits(layer_data *dev_data, const char *func_name, uint32_t mem_range_count,
10114ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                                                  const VkMappedMemoryRange *mem_ranges) {
10115ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski    bool skip = false;
10116ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski    for (uint32_t i = 0; i < mem_range_count; ++i) {
10117ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski        uint64_t atom_size = dev_data->phys_dev_properties.properties.limits.nonCoherentAtomSize;
10118ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski        if (vk_safe_modulo(mem_ranges[i].offset, atom_size) != 0) {
10119df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
10120df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            reinterpret_cast<const uint64_t &>(mem_ranges->memory), __LINE__, VALIDATION_ERROR_00644, "MEM",
10121ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            "%s: Offset in pMemRanges[%d] is 0x%" PRIxLEAST64
10122ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            ", which is not a multiple of VkPhysicalDeviceLimits::nonCoherentAtomSize (0x%" PRIxLEAST64 "). %s",
10123ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            func_name, i, mem_ranges[i].offset, atom_size, validation_error_map[VALIDATION_ERROR_00644]);
10124ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski        }
10125ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski        if ((mem_ranges[i].size != VK_WHOLE_SIZE) && (vk_safe_modulo(mem_ranges[i].size, atom_size) != 0)) {
10126df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
10127df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            reinterpret_cast<const uint64_t &>(mem_ranges->memory), __LINE__, VALIDATION_ERROR_00645, "MEM",
10128ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            "%s: Size in pMemRanges[%d] is 0x%" PRIxLEAST64
10129ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            ", which is not a multiple of VkPhysicalDeviceLimits::nonCoherentAtomSize (0x%" PRIxLEAST64 "). %s",
10130ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            func_name, i, mem_ranges[i].size, atom_size, validation_error_map[VALIDATION_ERROR_00645]);
10131ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski        }
10132ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski    }
10133ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski    return skip;
10134ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski}
10135ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski
1013680e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinskistatic bool PreCallValidateFlushMappedMemoryRanges(layer_data *dev_data, uint32_t mem_range_count,
1013780e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski                                                   const VkMappedMemoryRange *mem_ranges) {
1013880e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    bool skip = false;
1013980e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    std::lock_guard<std::mutex> lock(global_lock);
1014080e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    skip |= ValidateAndCopyNoncoherentMemoryToDriver(dev_data, mem_range_count, mem_ranges);
1014180e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    skip |= validateMemoryIsMapped(dev_data, "vkFlushMappedMemoryRanges", mem_range_count, mem_ranges);
1014280e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    return skip;
1014380e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski}
1014480e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski
10145bba0de708d942e9a2187158915856995db1c5a4dMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL FlushMappedMemoryRanges(VkDevice device, uint32_t memRangeCount,
10146bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                                       const VkMappedMemoryRange *pMemRanges) {
101475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
1014856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
101495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1015080e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    if (!PreCallValidateFlushMappedMemoryRanges(dev_data, memRangeCount, pMemRanges)) {
101514a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.FlushMappedMemoryRanges(device, memRangeCount, pMemRanges);
101525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
101535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
101545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
101555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1015680e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinskistatic bool PreCallValidateInvalidateMappedMemoryRanges(layer_data *dev_data, uint32_t mem_range_count,
1015780e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski                                                        const VkMappedMemoryRange *mem_ranges) {
1015880e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    bool skip = false;
1015980e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    std::lock_guard<std::mutex> lock(global_lock);
1016080e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    skip |= validateMemoryIsMapped(dev_data, "vkInvalidateMappedMemoryRanges", mem_range_count, mem_ranges);
1016180e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    return skip;
1016280e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski}
1016380e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski
1016480e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinskistatic void PostCallRecordInvalidateMappedMemoryRanges(layer_data *dev_data, uint32_t mem_range_count,
1016580e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski                                                       const VkMappedMemoryRange *mem_ranges) {
1016680e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    std::lock_guard<std::mutex> lock(global_lock);
1016780e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    // Update our shadow copy with modified driver data
1016880e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    CopyNoncoherentMemoryFromDriver(dev_data, mem_range_count, mem_ranges);
1016980e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski}
1017080e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski
10171bba0de708d942e9a2187158915856995db1c5a4dMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL InvalidateMappedMemoryRanges(VkDevice device, uint32_t memRangeCount,
10172bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                                            const VkMappedMemoryRange *pMemRanges) {
101735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
1017456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
101755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1017680e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    if (!PreCallValidateInvalidateMappedMemoryRanges(dev_data, memRangeCount, pMemRanges)) {
101774a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.InvalidateMappedMemoryRanges(device, memRangeCount, pMemRanges);
1017880e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski        if (result == VK_SUCCESS) {
1017980e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski            PostCallRecordInvalidateMappedMemoryRanges(dev_data, memRangeCount, pMemRanges);
1018080e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski        }
101815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
101825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
101835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
101845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10185160335c453ec51cc48bdef78e8befdb3c86ff292Cort Strattonstatic bool PreCallValidateBindImageMemory(layer_data *dev_data, VkImage image, IMAGE_STATE *image_state, VkDeviceMemory mem,
10186160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                                           VkDeviceSize memoryOffset) {
101870109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski    bool skip = false;
101881facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (image_state) {
10189160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        std::unique_lock<std::mutex> lock(global_lock);
1019094c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis        // Track objects tied to memory
1019147aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski        uint64_t image_handle = reinterpret_cast<uint64_t &>(image);
10192c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        skip = ValidateSetMemBinding(dev_data, mem, image_handle, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, "vkBindImageMemory()");
10193ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis        if (!image_state->memory_requirements_checked) {
10194ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            // There's not an explicit requirement in the spec to call vkGetImageMemoryRequirements() prior to calling
10195341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton            // BindImageMemory but it's implied in that memory being bound must conform with VkMemoryRequirements from
10196341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton            // vkGetImageMemoryRequirements()
101970109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
101980109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski                            image_handle, __LINE__, DRAWSTATE_INVALID_IMAGE, "DS",
101990109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski                            "vkBindImageMemory(): Binding memory to image 0x%" PRIxLEAST64
102000109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski                            " but vkGetImageMemoryRequirements() has not been called on that image.",
102010109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski                            image_handle);
10202ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            // Make the call for them so we can verify the state
10203ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            lock.unlock();
10204341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton            dev_data->dispatch_table.GetImageMemoryRequirements(dev_data->device, image, &image_state->requirements);
10205ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            lock.lock();
10206ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis        }
1020747aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
102080ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        // Validate bound memory range information
102099a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto mem_info = GetMemObjInfo(dev_data, mem);
1021057fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        if (mem_info) {
102110ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton            skip |= ValidateInsertImageMemoryRange(dev_data, image, mem_info, memoryOffset, image_state->requirements,
102120ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                                   image_state->createInfo.tiling == VK_IMAGE_TILING_LINEAR, "vkBindImageMemory()");
1021374300755ed9ec780d6073af71e47f201217008d6Cort Stratton            skip |= ValidateMemoryTypes(dev_data, mem_info, image_state->requirements.memoryTypeBits, "vkBindImageMemory()",
102140109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski                                        VALIDATION_ERROR_00806);
1021547aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski        }
10216160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton
10217160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        // Validate memory requirements alignment
10218160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        if (vk_safe_modulo(memoryOffset, image_state->requirements.alignment) != 0) {
10219160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
10220160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            image_handle, __LINE__, VALIDATION_ERROR_02178, "DS",
10221160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            "vkBindImageMemory(): memoryOffset is 0x%" PRIxLEAST64
10222160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            " but must be an integer multiple of the "
10223160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            "VkMemoryRequirements::alignment value 0x%" PRIxLEAST64
10224160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            ", returned from a call to vkGetImageMemoryRequirements with image. %s",
10225160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            memoryOffset, image_state->requirements.alignment, validation_error_map[VALIDATION_ERROR_02178]);
10226160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        }
10227160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton
10228160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        // Validate memory requirements size
10229160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        if (image_state->requirements.size > mem_info->alloc_info.allocationSize - memoryOffset) {
10230160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
10231160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            image_handle, __LINE__, VALIDATION_ERROR_02179, "DS",
10232160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            "vkBindImageMemory(): memory size minus memoryOffset is 0x%" PRIxLEAST64
10233160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            " but must be at least as large as "
10234160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            "VkMemoryRequirements::size value 0x%" PRIxLEAST64
10235160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            ", returned from a call to vkGetImageMemoryRequirements with image. %s",
10236160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            mem_info->alloc_info.allocationSize - memoryOffset, image_state->requirements.size,
10237160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            validation_error_map[VALIDATION_ERROR_02179]);
10238160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        }
10239341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    }
10240341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    return skip;
10241341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton}
1024247aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
10243160335c453ec51cc48bdef78e8befdb3c86ff292Cort Strattonstatic void PostCallRecordBindImageMemory(layer_data *dev_data, VkImage image, IMAGE_STATE *image_state, VkDeviceMemory mem,
10244160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                                          VkDeviceSize memoryOffset) {
10245341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    if (image_state) {
10246160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        std::unique_lock<std::mutex> lock(global_lock);
102470ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        // Track bound memory range information
102480ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        auto mem_info = GetMemObjInfo(dev_data, mem);
102490ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        if (mem_info) {
102500ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton            InsertImageMemoryRange(dev_data, image, mem_info, memoryOffset, image_state->requirements,
102510ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                   image_state->createInfo.tiling == VK_IMAGE_TILING_LINEAR);
102520ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        }
102530ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
10254c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        // Track objects tied to memory
10255c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        uint64_t image_handle = reinterpret_cast<uint64_t &>(image);
10256c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        SetMemBinding(dev_data, mem, image_handle, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, "vkBindImageMemory()");
10257c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton
10258341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton        image_state->binding.mem = mem;
10259341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton        image_state->binding.offset = memoryOffset;
10260341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton        image_state->binding.size = image_state->requirements.size;
10261341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    }
10262341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton}
10263341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton
10264341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort StrattonVKAPI_ATTR VkResult VKAPI_CALL BindImageMemory(VkDevice device, VkImage image, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
10265341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
10266341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
10267160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton    auto image_state = GetImageState(dev_data, image);
10268160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton    bool skip = PreCallValidateBindImageMemory(dev_data, image, image_state, mem, memoryOffset);
10269341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    if (!skip) {
10270341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton        result = dev_data->dispatch_table.BindImageMemory(device, image, mem, memoryOffset);
10271341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton        if (result == VK_SUCCESS) {
10272160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton            PostCallRecordBindImageMemory(dev_data, image, image_state, mem, memoryOffset);
1027394c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis        }
102745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
102755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
102765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
102775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1027889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL SetEvent(VkDevice device, VkEvent event) {
102793ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis    bool skip_call = false;
102803ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
1028156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
10282b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
102839a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto event_state = GetEventNode(dev_data, event);
102844710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis    if (event_state) {
102854710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        event_state->needsSignaled = false;
102864710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        event_state->stageMask = VK_PIPELINE_STAGE_HOST_BIT;
102874710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        if (event_state->write_in_use) {
102883ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT,
102893ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis                                 reinterpret_cast<const uint64_t &>(event), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
10290414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                                 "Cannot call vkSetEvent() on event 0x%" PRIxLEAST64 " that is already in use by a command buffer.",
102913ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis                                 reinterpret_cast<const uint64_t &>(event));
102923ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis        }
102933ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis    }
10294b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
102956fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    // Host setting event is visible to all queues immediately so update stageMask for any queue that's seen this event
102966fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    // TODO : For correctness this needs separate fix to verify that app doesn't make incorrect assumptions about the
102976fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    // ordering of this command in relation to vkCmd[Set|Reset]Events (see GH297)
102986fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    for (auto queue_data : dev_data->queueMap) {
102996fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis        auto event_entry = queue_data.second.eventToStageMap.find(event);
103006fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis        if (event_entry != queue_data.second.eventToStageMap.end()) {
103016fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis            event_entry->second |= VK_PIPELINE_STAGE_HOST_BIT;
103026fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis        }
103036fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    }
10304cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) result = dev_data->dispatch_table.SetEvent(device, event);
103055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
103065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
103075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10308bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL QueueBindSparse(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo *pBindInfo,
10309bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                               VkFence fence) {
1031056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
103115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
10312e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool skip_call = false;
10313b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
103149a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pFence = GetFenceNode(dev_data, fence);
103159a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pQueue = GetQueueState(dev_data, queue);
10316651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
103174b38d3aa8b6be6a7f5bebb472ab439da0562824fTobin Ehlis    // First verify that fence is not in use
10318651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    skip_call |= ValidateFenceForSubmit(dev_data, pFence);
10319651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
103209867daedbf52debc77d6568162ee21e071699b80Chris Forbes    if (pFence) {
1032193ccd9708dad3ffb58a3fc09a3d61cc5fe1569f8Mark Lobodzinski        SubmitFence(pQueue, pFence, std::max(1u, bindInfoCount));
103224b38d3aa8b6be6a7f5bebb472ab439da0562824fTobin Ehlis    }
10323651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
103241344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis    for (uint32_t bindIdx = 0; bindIdx < bindInfoCount; ++bindIdx) {
103251344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        const VkBindSparseInfo &bindInfo = pBindInfo[bindIdx];
103265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Track objects tied to memory
103271344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t j = 0; j < bindInfo.bufferBindCount; j++) {
103281344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis            for (uint32_t k = 0; k < bindInfo.pBufferBinds[j].bindCount; k++) {
10329f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                auto sparse_binding = bindInfo.pBufferBinds[j].pBinds[k];
10330f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                if (SetSparseMemBinding(dev_data, {sparse_binding.memory, sparse_binding.memoryOffset, sparse_binding.size},
10331f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                                        (uint64_t)bindInfo.pBufferBinds[j].buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
10332f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                                        "vkQueueBindSparse"))
10333e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                    skip_call = true;
103345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
103355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
103361344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t j = 0; j < bindInfo.imageOpaqueBindCount; j++) {
103371344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis            for (uint32_t k = 0; k < bindInfo.pImageOpaqueBinds[j].bindCount; k++) {
10338f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                auto sparse_binding = bindInfo.pImageOpaqueBinds[j].pBinds[k];
10339f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                if (SetSparseMemBinding(dev_data, {sparse_binding.memory, sparse_binding.memoryOffset, sparse_binding.size},
10340f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                                        (uint64_t)bindInfo.pImageOpaqueBinds[j].image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
10341f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                                        "vkQueueBindSparse"))
10342e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                    skip_call = true;
103435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
103445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
103451344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t j = 0; j < bindInfo.imageBindCount; j++) {
103461344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis            for (uint32_t k = 0; k < bindInfo.pImageBinds[j].bindCount; k++) {
10347f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                auto sparse_binding = bindInfo.pImageBinds[j].pBinds[k];
10348f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                // TODO: This size is broken for non-opaque bindings, need to update to comprehend full sparse binding data
10349f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                VkDeviceSize size = sparse_binding.extent.depth * sparse_binding.extent.height * sparse_binding.extent.width * 4;
10350f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                if (SetSparseMemBinding(dev_data, {sparse_binding.memory, sparse_binding.memoryOffset, size},
10351f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                                        (uint64_t)bindInfo.pImageBinds[j].image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
10352f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                                        "vkQueueBindSparse"))
10353e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                    skip_call = true;
103545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
103555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
103569867daedbf52debc77d6568162ee21e071699b80Chris Forbes
103579867daedbf52debc77d6568162ee21e071699b80Chris Forbes        std::vector<SEMAPHORE_WAIT> semaphore_waits;
103589867daedbf52debc77d6568162ee21e071699b80Chris Forbes        std::vector<VkSemaphore> semaphore_signals;
103591344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t i = 0; i < bindInfo.waitSemaphoreCount; ++i) {
1036001a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            VkSemaphore semaphore = bindInfo.pWaitSemaphores[i];
103619a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
1036201a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            if (pSemaphore) {
1036301a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes                if (pSemaphore->signaled) {
103649867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    if (pSemaphore->signaler.first != VK_NULL_HANDLE) {
103659867daedbf52debc77d6568162ee21e071699b80Chris Forbes                        semaphore_waits.push_back({semaphore, pSemaphore->signaler.first, pSemaphore->signaler.second});
103669867daedbf52debc77d6568162ee21e071699b80Chris Forbes                        pSemaphore->in_use.fetch_add(1);
103679867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    }
103689867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->signaler.first = VK_NULL_HANDLE;
1036901a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes                    pSemaphore->signaled = false;
103701344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                } else {
10371226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    skip_call |= log_msg(
10372226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
10373226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        reinterpret_cast<const uint64_t &>(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
10374226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "vkQueueBindSparse: Queue 0x%p is waiting on semaphore 0x%" PRIx64 " that has no way to be signaled.",
10375226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        queue, reinterpret_cast<const uint64_t &>(semaphore));
103765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
103775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
103785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
103791344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t i = 0; i < bindInfo.signalSemaphoreCount; ++i) {
1038001a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            VkSemaphore semaphore = bindInfo.pSignalSemaphores[i];
103819a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
1038201a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            if (pSemaphore) {
1038301a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes                if (pSemaphore->signaled) {
103845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    skip_call =
103855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
103861344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                                reinterpret_cast<const uint64_t &>(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
10387226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                "vkQueueBindSparse: Queue 0x%p is signaling semaphore 0x%" PRIx64
103881344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                                ", but that semaphore is already signaled.",
10389226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                queue, reinterpret_cast<const uint64_t &>(semaphore));
10390bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                } else {
103919867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->signaler.first = queue;
103929867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->signaler.second = pQueue->seq + pQueue->submissions.size() + 1;
103939867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->signaled = true;
103949867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->in_use.fetch_add(1);
103959867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    semaphore_signals.push_back(semaphore);
103969867daedbf52debc77d6568162ee21e071699b80Chris Forbes                }
103975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
103985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
103999867daedbf52debc77d6568162ee21e071699b80Chris Forbes
10400bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pQueue->submissions.emplace_back(std::vector<VkCommandBuffer>(), semaphore_waits, semaphore_signals,
104019867daedbf52debc77d6568162ee21e071699b80Chris Forbes                                         bindIdx == bindInfoCount - 1 ? fence : VK_NULL_HANDLE);
104025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
104039867daedbf52debc77d6568162ee21e071699b80Chris Forbes
104049867daedbf52debc77d6568162ee21e071699b80Chris Forbes    if (pFence && !bindInfoCount) {
104059867daedbf52debc77d6568162ee21e071699b80Chris Forbes        // No work to do, just dropping a fence in the queue by itself.
10406bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pQueue->submissions.emplace_back(std::vector<VkCommandBuffer>(), std::vector<SEMAPHORE_WAIT>(), std::vector<VkSemaphore>(),
104079867daedbf52debc77d6568162ee21e071699b80Chris Forbes                                         fence);
104089867daedbf52debc77d6568162ee21e071699b80Chris Forbes    }
104099867daedbf52debc77d6568162ee21e071699b80Chris Forbes
10410b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
104115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10412cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) return dev_data->dispatch_table.QueueBindSparse(queue, bindInfoCount, pBindInfo, fence);
104135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
104145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
104155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
104165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1041789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateSemaphore(VkDevice device, const VkSemaphoreCreateInfo *pCreateInfo,
1041889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                               const VkAllocationCallbacks *pAllocator, VkSemaphore *pSemaphore) {
1041956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
104204a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateSemaphore(device, pCreateInfo, pAllocator, pSemaphore);
104215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
10422b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
10423bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        SEMAPHORE_NODE *sNode = &dev_data->semaphoreMap[*pSemaphore];
104249867daedbf52debc77d6568162ee21e071699b80Chris Forbes        sNode->signaler.first = VK_NULL_HANDLE;
104259867daedbf52debc77d6568162ee21e071699b80Chris Forbes        sNode->signaler.second = 0;
104261344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        sNode->signaled = false;
104275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
104285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
104295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
104305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10431bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateEvent(VkDevice device, const VkEventCreateInfo *pCreateInfo,
10432bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           const VkAllocationCallbacks *pAllocator, VkEvent *pEvent) {
1043356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
104344a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateEvent(device, pCreateInfo, pAllocator, pEvent);
104355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
10436b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
104375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->eventMap[*pEvent].needsSignaled = false;
10438293ecfc5e69ed3978a8c04518166d828294870a4Tony Barbour        dev_data->eventMap[*pEvent].write_in_use = 0;
104395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->eventMap[*pEvent].stageMask = VkPipelineStageFlags(0);
104405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
104415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
104425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
104435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
104449ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinskistatic bool PreCallValidateCreateSwapchainKHR(layer_data *dev_data, const char *func_name,
104459ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                                              VkSwapchainCreateInfoKHR const *pCreateInfo, SURFACE_STATE *surface_state,
104469ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                                              SWAPCHAIN_NODE *old_swapchain_state) {
10447d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    auto most_recent_swapchain = surface_state->swapchain ? surface_state->swapchain : surface_state->old_swapchain;
10448d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes
104494bd5f453535de3d3423ff1f9995b4acb15f791d2Chris Forbes    // TODO: revisit this. some of these rules are being relaxed.
10450d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    if (most_recent_swapchain != old_swapchain_state || (surface_state->old_swapchain && surface_state->swapchain)) {
10451d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
10452d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes                    reinterpret_cast<uint64_t>(dev_data->device), __LINE__, DRAWSTATE_SWAPCHAIN_ALREADY_EXISTS, "DS",
104539ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    "%s: surface has an existing swapchain other than oldSwapchain", func_name))
10454d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes            return true;
10455d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    }
10456d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    if (old_swapchain_state && old_swapchain_state->createInfo.surface != pCreateInfo->surface) {
10457d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
10458d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes                    reinterpret_cast<uint64_t const &>(pCreateInfo->oldSwapchain), __LINE__, DRAWSTATE_SWAPCHAIN_WRONG_SURFACE,
104599ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    "DS", "%s: pCreateInfo->oldSwapchain's surface is not pCreateInfo->surface", func_name))
10460d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes            return true;
10461d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    }
104629a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(dev_data->instance_data, dev_data->physical_device);
104637de258f87ca1192db116a66b209253793d276ebcChris Forbes    if (physical_device_state->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState == UNCALLED) {
104647de258f87ca1192db116a66b209253793d276ebcChris Forbes        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
104657de258f87ca1192db116a66b209253793d276ebcChris Forbes                    reinterpret_cast<uint64_t>(dev_data->physical_device), __LINE__, DRAWSTATE_SWAPCHAIN_CREATE_BEFORE_QUERY, "DS",
104669ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    "%s: surface capabilities not retrieved for this physical device", func_name))
104677de258f87ca1192db116a66b209253793d276ebcChris Forbes            return true;
10468cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    } else {  // have valid capabilities
104695c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        auto &capabilities = physical_device_state->surfaceCapabilities;
104709ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->minImageCount against VkSurfaceCapabilitiesKHR::{min|max}ImageCount:
104712fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen        if (pCreateInfo->minImageCount < capabilities.minImageCount) {
104722fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
104732fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02331, "DS",
104749ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with minImageCount = %d, which is outside the bounds returned "
104752fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        "by vkGetPhysicalDeviceSurfaceCapabilitiesKHR() (i.e. minImageCount = %d, maxImageCount = %d). %s",
104769ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->minImageCount, capabilities.minImageCount, capabilities.maxImageCount,
104772fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        validation_error_map[VALIDATION_ERROR_02331]))
104782fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                return true;
104792fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen        }
104802fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen
104812fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen        if ((capabilities.maxImageCount > 0) && (pCreateInfo->minImageCount > capabilities.maxImageCount)) {
104825c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
104832fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02332, "DS",
104849ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with minImageCount = %d, which is outside the bounds returned "
104852fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        "by vkGetPhysicalDeviceSurfaceCapabilitiesKHR() (i.e. minImageCount = %d, maxImageCount = %d). %s",
104869ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->minImageCount, capabilities.minImageCount, capabilities.maxImageCount,
104872fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        validation_error_map[VALIDATION_ERROR_02332]))
104885c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
104895c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
104902fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen
104919ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->imageExtent against VkSurfaceCapabilitiesKHR::{current|min|max}ImageExtent:
104922e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill        if ((capabilities.currentExtent.width == kSurfaceSizeFromSwapchain) &&
104932e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill            ((pCreateInfo->imageExtent.width < capabilities.minImageExtent.width) ||
104942e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill             (pCreateInfo->imageExtent.width > capabilities.maxImageExtent.width) ||
104952e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill             (pCreateInfo->imageExtent.height < capabilities.minImageExtent.height) ||
104962e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill             (pCreateInfo->imageExtent.height > capabilities.maxImageExtent.height))) {
104975c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
104982fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02334, "DS",
104999ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with imageExtent = (%d,%d), which is outside the bounds returned by "
105009ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "vkGetPhysicalDeviceSurfaceCapabilitiesKHR(): currentExtent = (%d,%d), minImageExtent = (%d,%d), "
105019ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "maxImageExtent = (%d,%d). %s",
105029ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->imageExtent.width, pCreateInfo->imageExtent.height,
105039ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        capabilities.currentExtent.width, capabilities.currentExtent.height, capabilities.minImageExtent.width,
105049ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        capabilities.minImageExtent.height, capabilities.maxImageExtent.width, capabilities.maxImageExtent.height,
105052fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        validation_error_map[VALIDATION_ERROR_02334]))
105065c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
105075c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
105082e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill        if ((capabilities.currentExtent.width != kSurfaceSizeFromSwapchain) &&
105092e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill            ((pCreateInfo->imageExtent.width != capabilities.currentExtent.width) ||
105102e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill             (pCreateInfo->imageExtent.height != capabilities.currentExtent.height))) {
105115c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
105122fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02334, "DS",
105139ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with imageExtent = (%d,%d), which is not equal to the currentExtent = (%d,%d) returned by "
105149ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "vkGetPhysicalDeviceSurfaceCapabilitiesKHR(). %s",
105159ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->imageExtent.width, pCreateInfo->imageExtent.height,
105169ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        capabilities.currentExtent.width, capabilities.currentExtent.height,
105172fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        validation_error_map[VALIDATION_ERROR_02334]))
105185c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
105195c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
105209ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // pCreateInfo->preTransform should have exactly one bit set, and that bit must also be set in
105219ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // VkSurfaceCapabilitiesKHR::supportedTransforms.
105225c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        if (!pCreateInfo->preTransform || (pCreateInfo->preTransform & (pCreateInfo->preTransform - 1)) ||
105235c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            !(pCreateInfo->preTransform & capabilities.supportedTransforms)) {
105249ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            // This is an error situation; one for which we'd like to give the developer a helpful, multi-line error message.  Build
105259ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            // it up a little at a time, and then log it:
105265c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            std::string errorString = "";
105275c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            char str[1024];
105285c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            // Here's the first part of the message:
105299ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            sprintf(str, "%s called with a non-supported pCreateInfo->preTransform (i.e. %s).  Supported values are:\n", func_name,
105305c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    string_VkSurfaceTransformFlagBitsKHR(pCreateInfo->preTransform));
105315c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            errorString += str;
105325c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            for (int i = 0; i < 32; i++) {
105335c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                // Build up the rest of the message:
105345c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                if ((1 << i) & capabilities.supportedTransforms) {
105355c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    const char *newStr = string_VkSurfaceTransformFlagBitsKHR((VkSurfaceTransformFlagBitsKHR)(1 << i));
105365c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    sprintf(str, "    %s\n", newStr);
105375c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    errorString += str;
105385c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                }
105395c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            }
105405c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            // Log the message that we've built up:
105415c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
105422fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t &>(dev_data->device), __LINE__, VALIDATION_ERROR_02339, "DS", "%s. %s",
105432fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        errorString.c_str(), validation_error_map[VALIDATION_ERROR_02339]))
105445c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
105455c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
105467b0d28d116977b91892f354e002edd760bdb86cbChris Forbes
105479ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // pCreateInfo->compositeAlpha should have exactly one bit set, and that bit must also be set in
105489ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // VkSurfaceCapabilitiesKHR::supportedCompositeAlpha
105495c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        if (!pCreateInfo->compositeAlpha || (pCreateInfo->compositeAlpha & (pCreateInfo->compositeAlpha - 1)) ||
105505c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            !((pCreateInfo->compositeAlpha) & capabilities.supportedCompositeAlpha)) {
105519ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            // This is an error situation; one for which we'd like to give the developer a helpful, multi-line error message.  Build
105529ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            // it up a little at a time, and then log it:
105535c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            std::string errorString = "";
105545c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            char str[1024];
105555c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            // Here's the first part of the message:
105569ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            sprintf(str, "%s called with a non-supported pCreateInfo->compositeAlpha (i.e. %s).  Supported values are:\n",
105579ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    func_name, string_VkCompositeAlphaFlagBitsKHR(pCreateInfo->compositeAlpha));
105585c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            errorString += str;
105595c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            for (int i = 0; i < 32; i++) {
105605c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                // Build up the rest of the message:
105615c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                if ((1 << i) & capabilities.supportedCompositeAlpha) {
105625c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    const char *newStr = string_VkCompositeAlphaFlagBitsKHR((VkCompositeAlphaFlagBitsKHR)(1 << i));
105635c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    sprintf(str, "    %s\n", newStr);
105645c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    errorString += str;
105655c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                }
105665c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            }
105675c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            // Log the message that we've built up:
105685c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
105692fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t &>(dev_data->device), __LINE__, VALIDATION_ERROR_02340, "DS", "%s. %s",
105702fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        errorString.c_str(), validation_error_map[VALIDATION_ERROR_02340]))
105715c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
105725c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
105739ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->imageArrayLayers against VkSurfaceCapabilitiesKHR::maxImageArrayLayers:
105745c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        if ((pCreateInfo->imageArrayLayers < 1) || (pCreateInfo->imageArrayLayers > capabilities.maxImageArrayLayers)) {
105755c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
105762fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02335, "DS",
105779ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with a non-supported imageArrayLayers (i.e. %d).  Minimum value is 1, maximum value is %d. %s",
105789ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->imageArrayLayers, capabilities.maxImageArrayLayers,
105792fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        validation_error_map[VALIDATION_ERROR_02335]))
105805c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
105815c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
105829ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->imageUsage against VkSurfaceCapabilitiesKHR::supportedUsageFlags:
105835c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        if (pCreateInfo->imageUsage != (pCreateInfo->imageUsage & capabilities.supportedUsageFlags)) {
105845c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
105852fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02336, "DS",
105869ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with a non-supported pCreateInfo->imageUsage (i.e. 0x%08x).  Supported flag bits are 0x%08x. %s",
105879ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->imageUsage, capabilities.supportedUsageFlags,
105889ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        validation_error_map[VALIDATION_ERROR_02336]))
105895c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
105905c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
105917de258f87ca1192db116a66b209253793d276ebcChris Forbes    }
10592d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes
105939ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski    // Validate pCreateInfo values with the results of vkGetPhysicalDeviceSurfaceFormatsKHR():
105945faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    if (physical_device_state->vkGetPhysicalDeviceSurfaceFormatsKHRState != QUERY_DETAILS) {
105955faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
105965faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    reinterpret_cast<uint64_t>(dev_data->device), __LINE__, DRAWSTATE_SWAPCHAIN_CREATE_BEFORE_QUERY, "DS",
105979ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    "%s called before calling vkGetPhysicalDeviceSurfaceFormatsKHR().", func_name))
105985faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            return true;
105995faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    } else {
106009ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->imageFormat against VkSurfaceFormatKHR::format:
106015faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        bool foundFormat = false;
106025faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        bool foundColorSpace = false;
106035faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        bool foundMatch = false;
106045faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        for (auto const &format : physical_device_state->surface_formats) {
106055faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            if (pCreateInfo->imageFormat == format.format) {
106069ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                // Validate pCreateInfo->imageColorSpace against VkSurfaceFormatKHR::colorSpace:
106075faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                foundFormat = true;
106085faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                if (pCreateInfo->imageColorSpace == format.colorSpace) {
106095faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    foundMatch = true;
106105faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    break;
106115faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                }
106125faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            } else {
106135faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                if (pCreateInfo->imageColorSpace == format.colorSpace) {
106145faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    foundColorSpace = true;
106155faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                }
106165faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            }
106175faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        }
106185faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        if (!foundMatch) {
106195faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            if (!foundFormat) {
106205faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
106212fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                            reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02333, "DS",
10622bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "%s called with a non-supported pCreateInfo->imageFormat (i.e. %d). %s", func_name,
10623bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            pCreateInfo->imageFormat, validation_error_map[VALIDATION_ERROR_02333]))
106242fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                    return true;
106252fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen            }
106262fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen            if (!foundColorSpace) {
106272fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
106282fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                            reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02333, "DS",
10629bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "%s called with a non-supported pCreateInfo->imageColorSpace (i.e. %d). %s", func_name,
10630bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            pCreateInfo->imageColorSpace, validation_error_map[VALIDATION_ERROR_02333]))
106315faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    return true;
106325faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            }
106335faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        }
106345faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    }
106355faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
106369ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski    // Validate pCreateInfo values with the results of vkGetPhysicalDeviceSurfacePresentModesKHR():
106379e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    if (physical_device_state->vkGetPhysicalDeviceSurfacePresentModesKHRState != QUERY_DETAILS) {
1063825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // FIFO is required to always be supported
106399e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        if (pCreateInfo->presentMode != VK_PRESENT_MODE_FIFO_KHR) {
106409e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
106419ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, DRAWSTATE_SWAPCHAIN_CREATE_BEFORE_QUERY, "DS",
106429ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called before calling vkGetPhysicalDeviceSurfacePresentModesKHR().", func_name))
106439e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                return true;
106449e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
106459e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    } else {
106469ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->presentMode against vkGetPhysicalDeviceSurfacePresentModesKHR():
10647bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        bool foundMatch = std::find(physical_device_state->present_modes.begin(), physical_device_state->present_modes.end(),
106489e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                                    pCreateInfo->presentMode) != physical_device_state->present_modes.end();
106499e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        if (!foundMatch) {
106509e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
106512fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_02341, "DS",
106529ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with a non-supported presentMode (i.e. %s). %s", func_name,
106532fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        string_VkPresentModeKHR(pCreateInfo->presentMode), validation_error_map[VALIDATION_ERROR_02341]))
106549e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                return true;
106559e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
106569e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    }
106579e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
10658d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    return false;
10659d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes}
10660d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes
10661261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinskistatic void PostCallRecordCreateSwapchainKHR(layer_data *dev_data, VkResult result, const VkSwapchainCreateInfoKHR *pCreateInfo,
10662261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski                                             VkSwapchainKHR *pSwapchain, SURFACE_STATE *surface_state,
10663261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski                                             SWAPCHAIN_NODE *old_swapchain_state) {
106645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
10665b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
10666ddc5201048319558ce66701163a4546ee957af19Chris Forbes        auto swapchain_state = unique_ptr<SWAPCHAIN_NODE>(new SWAPCHAIN_NODE(pCreateInfo, *pSwapchain));
10667ddc5201048319558ce66701163a4546ee957af19Chris Forbes        surface_state->swapchain = swapchain_state.get();
10668ddc5201048319558ce66701163a4546ee957af19Chris Forbes        dev_data->device_extensions.swapchainMap[*pSwapchain] = std::move(swapchain_state);
10669ddc5201048319558ce66701163a4546ee957af19Chris Forbes    } else {
10670ddc5201048319558ce66701163a4546ee957af19Chris Forbes        surface_state->swapchain = nullptr;
106715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10672ddc5201048319558ce66701163a4546ee957af19Chris Forbes    // Spec requires that even if CreateSwapchainKHR fails, oldSwapchain behaves as replaced.
106735b5488456e5afa0487f95b805a2aba59b13d69f4Chris Forbes    if (old_swapchain_state) {
106745b5488456e5afa0487f95b805a2aba59b13d69f4Chris Forbes        old_swapchain_state->replaced = true;
106755b5488456e5afa0487f95b805a2aba59b13d69f4Chris Forbes    }
10676ddc5201048319558ce66701163a4546ee957af19Chris Forbes    surface_state->old_swapchain = old_swapchain_state;
10677261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski    return;
10678261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski}
10679261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski
10680261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo,
10681261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski                                                  const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchain) {
1068256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
106839a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto surface_state = GetSurfaceState(dev_data->instance_data, pCreateInfo->surface);
106849a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto old_swapchain_state = GetSwapchainNode(dev_data, pCreateInfo->oldSwapchain);
10685261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski
106869ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski    if (PreCallValidateCreateSwapchainKHR(dev_data, "vkCreateSwapChainKHR()", pCreateInfo, surface_state, old_swapchain_state)) {
10687261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski        return VK_ERROR_VALIDATION_FAILED_EXT;
10688261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski    }
10689261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski
10690261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski    VkResult result = dev_data->dispatch_table.CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain);
10691261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski
10692261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski    PostCallRecordCreateSwapchainKHR(dev_data, result, pCreateInfo, pSwapchain, surface_state, old_swapchain_state);
10693ddc5201048319558ce66701163a4546ee957af19Chris Forbes
106945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
106955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
106965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10697bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks *pAllocator) {
1069856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
1069983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
107005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10701b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
107029a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto swapchain_data = GetSwapchainNode(dev_data, swapchain);
10703b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis    if (swapchain_data) {
10704b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis        if (swapchain_data->images.size() > 0) {
10705b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis            for (auto swapchain_image : swapchain_data->images) {
107065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                auto image_sub = dev_data->imageSubresourceMap.find(swapchain_image);
107075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (image_sub != dev_data->imageSubresourceMap.end()) {
107085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    for (auto imgsubpair : image_sub->second) {
107095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        auto image_item = dev_data->imageLayoutMap.find(imgsubpair);
107105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        if (image_item != dev_data->imageLayoutMap.end()) {
107115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                            dev_data->imageLayoutMap.erase(image_item);
107125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        }
107135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
107145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    dev_data->imageSubresourceMap.erase(image_sub);
107155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
1071683b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                skip_call =
10717f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                    ClearMemoryObjectBindings(dev_data, (uint64_t)swapchain_image, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT);
1071894c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis                dev_data->imageMap.erase(swapchain_image);
107195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
107205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
10721ddc5201048319558ce66701163a4546ee957af19Chris Forbes
107229a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto surface_state = GetSurfaceState(dev_data->instance_data, swapchain_data->createInfo.surface);
10723ddc5201048319558ce66701163a4546ee957af19Chris Forbes        if (surface_state) {
10724cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (surface_state->swapchain == swapchain_data) surface_state->swapchain = nullptr;
10725cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (surface_state->old_swapchain == swapchain_data) surface_state->old_swapchain = nullptr;
10726ddc5201048319558ce66701163a4546ee957af19Chris Forbes        }
10727ddc5201048319558ce66701163a4546ee957af19Chris Forbes
107285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->device_extensions.swapchainMap.erase(swapchain);
107295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10730b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
10731cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip_call) dev_data->dispatch_table.DestroySwapchainKHR(device, swapchain, pAllocator);
107325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
107335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10734bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pCount,
10735bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                     VkImage *pSwapchainImages) {
1073656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
107374a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.GetSwapchainImagesKHR(device, swapchain, pCount, pSwapchainImages);
107385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
107395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS && pSwapchainImages != NULL) {
107405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // This should never happen and is checked by param checker.
10741cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!pCount) return result;
10742b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
107435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const size_t count = *pCount;
107449a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto swapchain_node = GetSwapchainNode(dev_data, swapchain);
10745b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis        if (swapchain_node && !swapchain_node->images.empty()) {
107460801763633180d277d26a90343464bd11646056fTobin Ehlis            // TODO : Not sure I like the memcmp here, but it works
107470801763633180d277d26a90343464bd11646056fTobin Ehlis            const bool mismatch = (swapchain_node->images.size() != count ||
107480801763633180d277d26a90343464bd11646056fTobin Ehlis                                   memcmp(&swapchain_node->images[0], pSwapchainImages, sizeof(swapchain_node->images[0]) * count));
107495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (mismatch) {
107505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // TODO: Verify against Valid Usage section of extension
107515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
107525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        (uint64_t)swapchain, __LINE__, MEMTRACK_NONE, "SWAP_CHAIN",
10753414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                        "vkGetSwapchainInfoKHR(0x%" PRIx64
107545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        ", VK_SWAP_CHAIN_INFO_TYPE_PERSISTENT_IMAGES_KHR) returned mismatching data",
107555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        (uint64_t)(swapchain));
107565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
107575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
107585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < *pCount; ++i) {
107595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            IMAGE_LAYOUT_NODE image_layout_node;
107605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            image_layout_node.layout = VK_IMAGE_LAYOUT_UNDEFINED;
107615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            image_layout_node.format = swapchain_node->createInfo.imageFormat;
107626d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            // Add imageMap entries for each swapchain image
107636d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            VkImageCreateInfo image_ci = {};
10764eb6ea7587bdc06e98a89398f113fe3610d270dcbChris Forbes            image_ci.flags = 0;
10765eb6ea7587bdc06e98a89398f113fe3610d270dcbChris Forbes            image_ci.imageType = VK_IMAGE_TYPE_2D;
107666d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.format = swapchain_node->createInfo.imageFormat;
107676d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.extent.width = swapchain_node->createInfo.imageExtent.width;
107686d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.extent.height = swapchain_node->createInfo.imageExtent.height;
10769d1a9776c1a22ec99a3ef0dd44e7f85a78a04d1edTony Barbour            image_ci.extent.depth = 1;
10770eb6ea7587bdc06e98a89398f113fe3610d270dcbChris Forbes            image_ci.mipLevels = 1;
10771eb6ea7587bdc06e98a89398f113fe3610d270dcbChris Forbes            image_ci.arrayLayers = swapchain_node->createInfo.imageArrayLayers;
10772eb6ea7587bdc06e98a89398f113fe3610d270dcbChris Forbes            image_ci.samples = VK_SAMPLE_COUNT_1_BIT;
10773eb6ea7587bdc06e98a89398f113fe3610d270dcbChris Forbes            image_ci.tiling = VK_IMAGE_TILING_OPTIMAL;
10774eb6ea7587bdc06e98a89398f113fe3610d270dcbChris Forbes            image_ci.usage = swapchain_node->createInfo.imageUsage;
107756d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.sharingMode = swapchain_node->createInfo.imageSharingMode;
107761facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            dev_data->imageMap[pSwapchainImages[i]] = unique_ptr<IMAGE_STATE>(new IMAGE_STATE(pSwapchainImages[i], &image_ci));
107771facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            auto &image_state = dev_data->imageMap[pSwapchainImages[i]];
107781facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            image_state->valid = false;
10779e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis            image_state->binding.mem = MEMTRACKER_SWAP_CHAIN_IMAGE_KEY;
107805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            swapchain_node->images.push_back(pSwapchainImages[i]);
107815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            ImageSubresourcePair subpair = {pSwapchainImages[i], false, VkImageSubresource()};
107825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->imageSubresourceMap[pSwapchainImages[i]].push_back(subpair);
107835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->imageLayoutMap[subpair] = image_layout_node;
107845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->device_extensions.imageToSwapchainMap[pSwapchainImages[i]] = swapchain;
107855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
107865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
107875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
107885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
107895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1079089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo) {
1079156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
107925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool skip_call = false;
107935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
107946c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    std::lock_guard<std::mutex> lock(global_lock);
107959a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto queue_state = GetQueueState(dev_data, queue);
107961671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes
107976c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    for (uint32_t i = 0; i < pPresentInfo->waitSemaphoreCount; ++i) {
107989a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto pSemaphore = GetSemaphoreNode(dev_data, pPresentInfo->pWaitSemaphores[i]);
107996c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        if (pSemaphore && !pSemaphore->signaled) {
10800226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis            skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
10801226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS,
10802226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                 "DS", "Queue 0x%p is waiting on semaphore 0x%" PRIx64 " that has no way to be signaled.", queue,
10803226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                                 reinterpret_cast<const uint64_t &>(pPresentInfo->pWaitSemaphores[i]));
108045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
108056c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    }
10806249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis
108076c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    for (uint32_t i = 0; i < pPresentInfo->swapchainCount; ++i) {
108089a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto swapchain_data = GetSwapchainNode(dev_data, pPresentInfo->pSwapchains[i]);
10809a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes        if (swapchain_data) {
10810a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes            if (pPresentInfo->pImageIndices[i] >= swapchain_data->images.size()) {
10811bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                skip_call |= log_msg(
10812bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
10813bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    reinterpret_cast<uint64_t const &>(pPresentInfo->pSwapchains[i]), __LINE__, DRAWSTATE_SWAPCHAIN_INVALID_IMAGE,
10814bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "DS", "vkQueuePresentKHR: Swapchain image index too large (%u). There are only %u images in this swapchain.",
10815bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    pPresentInfo->pImageIndices[i], (uint32_t)swapchain_data->images.size());
10816bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            } else {
10817a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                auto image = swapchain_data->images[pPresentInfo->pImageIndices[i]];
108189a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto image_state = GetImageState(dev_data, image);
108191facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis                skip_call |= ValidateImageMemoryIsValid(dev_data, image_state, "vkQueuePresentKHR()");
10820a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes
108211facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis                if (!image_state->acquired) {
10822bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    skip_call |= log_msg(
10823bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
10824bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        reinterpret_cast<uint64_t const &>(pPresentInfo->pSwapchains[i]), __LINE__,
10825bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        DRAWSTATE_SWAPCHAIN_IMAGE_NOT_ACQUIRED, "DS",
10826bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        "vkQueuePresentKHR: Swapchain image index %u has not been acquired.", pPresentInfo->pImageIndices[i]);
10827a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                }
10828a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes
10829a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                vector<VkImageLayout> layouts;
10830a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                if (FindLayouts(dev_data, image, layouts)) {
10831a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                    for (auto layout : layouts) {
10832a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                        if (layout != VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) {
10833a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                            skip_call |=
108342fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT,
108352fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                        reinterpret_cast<uint64_t &>(queue), __LINE__, VALIDATION_ERROR_01964, "DS",
108362fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                        "Images passed to present must be in layout "
108372fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                        "VK_IMAGE_LAYOUT_PRESENT_SRC_KHR but is in %s. %s",
108382fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                        string_VkImageLayout(layout), validation_error_map[VALIDATION_ERROR_01964]);
10839a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                        }
108405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
108415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
108425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
108431671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes
108441671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            // All physical devices and queue families are required to be able
108451671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            // to present to any native window on Android; require the
108461671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            // application to have established support on any other platform.
108471671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            if (!dev_data->instance_data->androidSurfaceExtensionEnabled) {
108489a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto surface_state = GetSurfaceState(dev_data->instance_data, swapchain_data->createInfo.surface);
108491671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                auto support_it = surface_state->gpu_queue_support.find({dev_data->physical_device, queue_state->queueFamilyIndex});
108501671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes
108511671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                if (support_it == surface_state->gpu_queue_support.end()) {
108521671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                    skip_call |=
108531671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
108541671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                                reinterpret_cast<uint64_t const &>(pPresentInfo->pSwapchains[i]), __LINE__,
10855cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                DRAWSTATE_SWAPCHAIN_UNSUPPORTED_QUEUE, "DS",
10856cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                "vkQueuePresentKHR: Presenting image without calling "
10857cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                "vkGetPhysicalDeviceSurfaceSupportKHR");
108581671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                } else if (!support_it->second) {
10859cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip_call |= log_msg(
10860cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
10861cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        reinterpret_cast<uint64_t const &>(pPresentInfo->pSwapchains[i]), __LINE__, VALIDATION_ERROR_01961, "DS",
10862cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "vkQueuePresentKHR: Presenting image on queue that cannot "
10863cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "present to this surface. %s",
10864cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        validation_error_map[VALIDATION_ERROR_01961]);
108651671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                }
108661671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            }
108675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
108685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
108695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
108706c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    if (skip_call) {
108716c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        return VK_ERROR_VALIDATION_FAILED_EXT;
108726c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    }
108736c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes
108744a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.QueuePresentKHR(queue, pPresentInfo);
108756c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes
108766c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    if (result != VK_ERROR_VALIDATION_FAILED_EXT) {
108776c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        // Semaphore waits occur before error generation, if the call reached
108786c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        // the ICD. (Confirm?)
108796c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        for (uint32_t i = 0; i < pPresentInfo->waitSemaphoreCount; ++i) {
108809a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, pPresentInfo->pWaitSemaphores[i]);
108819867daedbf52debc77d6568162ee21e071699b80Chris Forbes            if (pSemaphore) {
108829867daedbf52debc77d6568162ee21e071699b80Chris Forbes                pSemaphore->signaler.first = VK_NULL_HANDLE;
108836c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes                pSemaphore->signaled = false;
108846c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes            }
108856c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        }
108869867daedbf52debc77d6568162ee21e071699b80Chris Forbes
10887220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes        for (uint32_t i = 0; i < pPresentInfo->swapchainCount; ++i) {
10888220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            // Note: this is imperfect, in that we can get confused about what
10889220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            // did or didn't succeed-- but if the app does that, it's confused
10890220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            // itself just as much.
10891220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            auto local_result = pPresentInfo->pResults ? pPresentInfo->pResults[i] : result;
10892220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes
10893cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (local_result != VK_SUCCESS && local_result != VK_SUBOPTIMAL_KHR) continue;  // this present didn't actually happen.
10894220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes
10895220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            // Mark the image as having been released to the WSI
108969a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto swapchain_data = GetSwapchainNode(dev_data, pPresentInfo->pSwapchains[i]);
10897220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            auto image = swapchain_data->images[pPresentInfo->pImageIndices[i]];
108989a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto image_state = GetImageState(dev_data, image);
108991facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            image_state->acquired = false;
10900220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes        }
10901220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes
109029867daedbf52debc77d6568162ee21e071699b80Chris Forbes        // Note: even though presentation is directed to a queue, there is no
109039867daedbf52debc77d6568162ee21e071699b80Chris Forbes        // direct ordering between QP and subsequent work, so QP (and its
109049867daedbf52debc77d6568162ee21e071699b80Chris Forbes        // semaphore waits) /never/ participate in any completion proof.
109056c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    }
109061344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
109075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
109085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
109095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10910c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinskistatic bool PreCallValidateCreateSharedSwapchainsKHR(layer_data *dev_data, uint32_t swapchainCount,
10911c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                     const VkSwapchainCreateInfoKHR *pCreateInfos, VkSwapchainKHR *pSwapchains,
10912c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                     std::vector<SURFACE_STATE *> &surface_state,
10913c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                     std::vector<SWAPCHAIN_NODE *> &old_swapchain_state) {
109140342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    if (pCreateInfos) {
10915c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski        std::lock_guard<std::mutex> lock(global_lock);
109160342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        for (uint32_t i = 0; i < swapchainCount; i++) {
109179a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            surface_state.push_back(GetSurfaceState(dev_data->instance_data, pCreateInfos[i].surface));
109189a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            old_swapchain_state.push_back(GetSwapchainNode(dev_data, pCreateInfos[i].oldSwapchain));
109199ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            std::stringstream func_name;
109209ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            func_name << "vkCreateSharedSwapchainsKHR[" << swapchainCount << "]";
10921bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (PreCallValidateCreateSwapchainKHR(dev_data, func_name.str().c_str(), &pCreateInfos[i], surface_state[i],
10922bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                  old_swapchain_state[i])) {
10923c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                return true;
109240342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            }
109250342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        }
109260342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    }
10927c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    return false;
10928c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski}
109290342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski
10930c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinskistatic void PostCallRecordCreateSharedSwapchainsKHR(layer_data *dev_data, VkResult result, uint32_t swapchainCount,
10931c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                    const VkSwapchainCreateInfoKHR *pCreateInfos, VkSwapchainKHR *pSwapchains,
10932c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                    std::vector<SURFACE_STATE *> &surface_state,
10933c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                    std::vector<SWAPCHAIN_NODE *> &old_swapchain_state) {
109340342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    if (VK_SUCCESS == result) {
109350342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        for (uint32_t i = 0; i < swapchainCount; i++) {
109360342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            auto swapchain_state = unique_ptr<SWAPCHAIN_NODE>(new SWAPCHAIN_NODE(&pCreateInfos[i], pSwapchains[i]));
109370342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            surface_state[i]->swapchain = swapchain_state.get();
109380342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            dev_data->device_extensions.swapchainMap[pSwapchains[i]] = std::move(swapchain_state);
109390342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        }
109400342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    } else {
109410342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        for (uint32_t i = 0; i < swapchainCount; i++) {
109420342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            surface_state[i]->swapchain = nullptr;
109430342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        }
109440342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    }
109450342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    // Spec requires that even if CreateSharedSwapchainKHR fails, oldSwapchain behaves as replaced.
109460342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    for (uint32_t i = 0; i < swapchainCount; i++) {
109470342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        if (old_swapchain_state[i]) {
109480342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            old_swapchain_state[i]->replaced = true;
109490342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        }
109500342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        surface_state[i]->old_swapchain = old_swapchain_state[i];
109510342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    }
10952c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    return;
10953c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski}
10954c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski
10955c6cd632d064579a64e61d8704b411d0e4ace7adaMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateSharedSwapchainsKHR(VkDevice device, uint32_t swapchainCount,
10956c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                         const VkSwapchainCreateInfoKHR *pCreateInfos,
10957c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                         const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchains) {
1095856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
10959c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    std::vector<SURFACE_STATE *> surface_state;
10960c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    std::vector<SWAPCHAIN_NODE *> old_swapchain_state;
10961c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski
10962c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    if (PreCallValidateCreateSharedSwapchainsKHR(dev_data, swapchainCount, pCreateInfos, pSwapchains, surface_state,
10963c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                 old_swapchain_state)) {
10964c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski        return VK_ERROR_VALIDATION_FAILED_EXT;
10965c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    }
10966c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski
10967c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    VkResult result =
10968c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski        dev_data->dispatch_table.CreateSharedSwapchainsKHR(device, swapchainCount, pCreateInfos, pAllocator, pSwapchains);
10969c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski
10970c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    PostCallRecordCreateSharedSwapchainsKHR(dev_data, result, swapchainCount, pCreateInfos, pSwapchains, surface_state,
10971c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                            old_swapchain_state);
109720342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski
10973c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young    return result;
10974c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young}
10975c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young
1097689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL AcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout,
1097789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                   VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex) {
1097856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
1097983b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
109801344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
10981b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
10982449670637ef4214b33018f497cf10daeff9dc85bChris Forbes
10983449670637ef4214b33018f497cf10daeff9dc85bChris Forbes    if (fence == VK_NULL_HANDLE && semaphore == VK_NULL_HANDLE) {
10984449670637ef4214b33018f497cf10daeff9dc85bChris Forbes        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
10985d17d86d15a733f1ec988956721ea4b7cdfb6771bChris Forbes                             reinterpret_cast<uint64_t &>(device), __LINE__, DRAWSTATE_SWAPCHAIN_NO_SYNC_FOR_ACQUIRE, "DS",
10986449670637ef4214b33018f497cf10daeff9dc85bChris Forbes                             "vkAcquireNextImageKHR: Semaphore and fence cannot both be VK_NULL_HANDLE. There would be no way "
10987449670637ef4214b33018f497cf10daeff9dc85bChris Forbes                             "to determine the completion of this operation.");
10988449670637ef4214b33018f497cf10daeff9dc85bChris Forbes    }
10989449670637ef4214b33018f497cf10daeff9dc85bChris Forbes
109909a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
10991f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    if (pSemaphore && pSemaphore->signaled) {
1099283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
109932fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                             reinterpret_cast<const uint64_t &>(semaphore), __LINE__, VALIDATION_ERROR_01952, "DS",
109942fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                             "vkAcquireNextImageKHR: Semaphore must not be currently signaled or in a wait state. %s",
109952fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                             validation_error_map[VALIDATION_ERROR_01952]);
109965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10997f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes
109989a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pFence = GetFenceNode(dev_data, fence);
10999f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    if (pFence) {
1100083b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis        skip_call |= ValidateFenceForSubmit(dev_data, pFence);
110015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
110024a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes
110039a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto swapchain_data = GetSwapchainNode(dev_data, swapchain);
11004fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes
11005fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes    if (swapchain_data->replaced) {
11006fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
11007fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes                             reinterpret_cast<uint64_t &>(swapchain), __LINE__, DRAWSTATE_SWAPCHAIN_REPLACED, "DS",
11008fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes                             "vkAcquireNextImageKHR: This swapchain has been replaced. The application can still "
11009fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes                             "present any images it has acquired, but cannot acquire any more.");
11010fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes    }
11011fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes
110129a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(dev_data->instance_data, dev_data->physical_device);
110134a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes    if (physical_device_state->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState != UNCALLED) {
110146569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski        uint64_t acquired_images = std::count_if(swapchain_data->images.begin(), swapchain_data->images.end(),
110159a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                                                 [=](VkImage image) { return GetImageState(dev_data, image)->acquired; });
110164a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes        if (acquired_images > swapchain_data->images.size() - physical_device_state->surfaceCapabilities.minImageCount) {
110176569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski            skip_call |=
110186569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
110196569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski                        reinterpret_cast<uint64_t const &>(swapchain), __LINE__, DRAWSTATE_SWAPCHAIN_TOO_MANY_IMAGES, "DS",
110206569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski                        "vkAcquireNextImageKHR: Application has already acquired the maximum number of images (0x%" PRIxLEAST64 ")",
110216569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski                        acquired_images);
110224a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes        }
110234a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes    }
1102475269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis
1102575269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis    if (swapchain_data->images.size() == 0) {
1102675269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis        skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
1102775269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis                             reinterpret_cast<uint64_t const &>(swapchain), __LINE__, DRAWSTATE_SWAPCHAIN_IMAGES_NOT_FOUND, "DS",
1102875269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis                             "vkAcquireNextImageKHR: No images found to acquire from. Application probably did not call "
1102975269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis                             "vkGetSwapchainImagesKHR after swapchain creation.");
1103075269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis    }
1103175269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis
11032b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
110331344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
11034cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
11035f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes
110364a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.AcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, pImageIndex);
11037f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes
11038f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    lock.lock();
11039f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    if (result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR) {
11040f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        if (pFence) {
11041f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes            pFence->state = FENCE_INFLIGHT;
11042cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            pFence->signaler.first = VK_NULL_HANDLE;  // ANI isn't on a queue, so this can't participate in a completion proof.
11043f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        }
11044f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes
11045f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        // A successful call to AcquireNextImageKHR counts as a signal operation on semaphore
11046f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        if (pSemaphore) {
11047f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes            pSemaphore->signaled = true;
110489867daedbf52debc77d6568162ee21e071699b80Chris Forbes            pSemaphore->signaler.first = VK_NULL_HANDLE;
11049f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        }
11050220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes
11051220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes        // Mark the image as acquired.
11052220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes        auto image = swapchain_data->images[*pImageIndex];
110539a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto image_state = GetImageState(dev_data, image);
110541facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        image_state->acquired = true;
110555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
11056f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    lock.unlock();
110571344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
110585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
110595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
110605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11061f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount,
11062f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski                                                        VkPhysicalDevice *pPhysicalDevices) {
1106383b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis    bool skip_call = false;
1106456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
11065bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    assert(instance_data);
11066219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes
11067bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    // For this instance, flag when vkEnumeratePhysicalDevices goes to QUERY_COUNT and then QUERY_DETAILS
11068bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    if (NULL == pPhysicalDevices) {
11069bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        instance_data->vkEnumeratePhysicalDevicesState = QUERY_COUNT;
11070f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    } else {
11071bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        if (UNCALLED == instance_data->vkEnumeratePhysicalDevicesState) {
11072bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            // Flag warning here. You can call this without having queried the count, but it may not be
11073bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            // robust on platforms with multiple physical devices.
11074bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            skip_call |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
11075bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis                                 VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, 0, __LINE__, DEVLIMITS_MISSING_QUERY_COUNT, "DL",
11076bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis                                 "Call sequence has vkEnumeratePhysicalDevices() w/ non-NULL pPhysicalDevices. You should first "
11077bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis                                 "call vkEnumeratePhysicalDevices() w/ NULL pPhysicalDevices to query pPhysicalDeviceCount.");
11078cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }  // TODO : Could also flag a warning if re-calling this function in QUERY_DETAILS state
11079bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        else if (instance_data->physical_devices_count != *pPhysicalDeviceCount) {
11080bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            // Having actual count match count from app is not a requirement, so this can be a warning
11081bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            skip_call |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
11082bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis                                 VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVLIMITS_COUNT_MISMATCH, "DL",
11083bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis                                 "Call to vkEnumeratePhysicalDevices() w/ pPhysicalDeviceCount value %u, but actual count "
11084bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis                                 "supported by this instance is %u.",
11085bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis                                 *pPhysicalDeviceCount, instance_data->physical_devices_count);
11086bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        }
11087bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        instance_data->vkEnumeratePhysicalDevicesState = QUERY_DETAILS;
11088f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    }
11089bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    if (skip_call) {
11090bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        return VK_ERROR_VALIDATION_FAILED_EXT;
11091bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    }
11092bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    VkResult result = instance_data->dispatch_table.EnumeratePhysicalDevices(instance, pPhysicalDeviceCount, pPhysicalDevices);
11093bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    if (NULL == pPhysicalDevices) {
11094bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        instance_data->physical_devices_count = *pPhysicalDeviceCount;
11095cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    } else if (result == VK_SUCCESS) {  // Save physical devices
11096bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        for (uint32_t i = 0; i < *pPhysicalDeviceCount; i++) {
11097bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            auto &phys_device_state = instance_data->physical_device_map[pPhysicalDevices[i]];
11098bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            phys_device_state.phys_device = pPhysicalDevices[i];
11099bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            // Init actual features for each physical device
11100bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            instance_data->dispatch_table.GetPhysicalDeviceFeatures(pPhysicalDevices[i], &phys_device_state.features);
11101bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        }
11102bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    }
11103bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    return result;
11104f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski}
11105f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
1110643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis// Common function to handle validation for GetPhysicalDeviceQueueFamilyProperties & 2KHR version
1110743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic bool ValidateCommonGetPhysicalDeviceQueueFamilyProperties(instance_layer_data *instance_data,
1110843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                 PHYSICAL_DEVICE_STATE *pd_state,
1110943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                 uint32_t *pQueueFamilyPropertyCount, bool qfp_null,
1111043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                 const char *count_var_name, const char *caller_name) {
1111143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    bool skip = false;
1111243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    if (qfp_null) {
1111343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        pd_state->vkGetPhysicalDeviceQueueFamilyPropertiesState = QUERY_COUNT;
1111443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    } else {
1111543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        // Verify that for each physical device, this function is called first with NULL pQueueFamilyProperties ptr in order to get
1111643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        // count
1111743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        if (UNCALLED == pd_state->vkGetPhysicalDeviceQueueFamilyPropertiesState) {
1111843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
1111943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                            VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVLIMITS_MISSING_QUERY_COUNT, "DL",
1112043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                            "Call sequence has %s() w/ non-NULL "
1112143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                            "pQueueFamilyProperties. You should first call %s() w/ "
1112243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                            "NULL pQueueFamilyProperties to query pCount.",
1112343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                            caller_name, caller_name);
1112443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        }
1112543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        // Then verify that pCount that is passed in on second call matches what was returned
1112643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        if (pd_state->queueFamilyPropertiesCount != *pQueueFamilyPropertyCount) {
1112743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            // TODO: this is not a requirement of the Valid Usage section for vkGetPhysicalDeviceQueueFamilyProperties, so
1112843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            // provide as warning
1112943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
1113043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                            VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVLIMITS_COUNT_MISMATCH, "DL",
1113143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                            "Call to %s() w/ %s value %u, but actual count supported by this physicalDevice is %u.", caller_name,
1113243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                            count_var_name, *pQueueFamilyPropertyCount, pd_state->queueFamilyPropertiesCount);
1113343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        }
1113443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        pd_state->vkGetPhysicalDeviceQueueFamilyPropertiesState = QUERY_DETAILS;
1113543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    }
1113643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    return skip;
1113743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1113843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1113943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic bool PreCallValidateGetPhysicalDeviceQueueFamilyProperties(instance_layer_data *instance_data,
1114043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                  PHYSICAL_DEVICE_STATE *pd_state, uint32_t *pCount,
1114143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                  VkQueueFamilyProperties *pQueueFamilyProperties) {
1114243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    return ValidateCommonGetPhysicalDeviceQueueFamilyProperties(instance_data, pd_state, pCount,
1114343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                (nullptr == pQueueFamilyProperties), "pCount",
1114443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                "vkGetPhysicalDeviceQueueFamilyProperties()");
1114543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1114643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1114743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic bool PreCallValidateGetPhysicalDeviceQueueFamilyProperties2KHR(instance_layer_data *instance_data,
1114843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                      PHYSICAL_DEVICE_STATE *pd_state,
1114943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                      uint32_t *pQueueFamilyPropertyCount,
1115043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                      VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
1115143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    return ValidateCommonGetPhysicalDeviceQueueFamilyProperties(instance_data, pd_state, pQueueFamilyPropertyCount,
1115243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                (nullptr == pQueueFamilyProperties), "pQueueFamilyPropertyCount",
1115343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                "vkGetPhysicalDeviceQueueFamilyProperties2KHR()");
1115443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1115543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1115643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis// Common function to update state for GetPhysicalDeviceQueueFamilyProperties & 2KHR version
1115743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic void StateUpdateCommonGetPhysicalDeviceQueueFamilyProperties(PHYSICAL_DEVICE_STATE *pd_state, uint32_t count,
1115843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                    VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
1115943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    if (!pQueueFamilyProperties) {
1116043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        pd_state->queueFamilyPropertiesCount = count;
1116143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    } else {  // Save queue family properties
1116243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        if (pd_state->queue_family_properties.size() < count) pd_state->queue_family_properties.resize(count);
1116343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        for (uint32_t i = 0; i < count; i++) {
1116443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            pd_state->queue_family_properties[i] = pQueueFamilyProperties[i].queueFamilyProperties;
1116543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        }
1116643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    }
1116743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1116843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1116943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic void PostCallRecordGetPhysicalDeviceQueueFamilyProperties(PHYSICAL_DEVICE_STATE *pd_state, uint32_t count,
1117043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                 VkQueueFamilyProperties *pQueueFamilyProperties) {
1117143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    VkQueueFamilyProperties2KHR *pqfp = nullptr;
1117243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    std::vector<VkQueueFamilyProperties2KHR> qfp;
1117343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    qfp.resize(count);
1117443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    if (pQueueFamilyProperties) {
1117543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        for (uint32_t i = 0; i < count; ++i) {
1117643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            qfp[i].sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR;
1117743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            qfp[i].pNext = nullptr;
1117843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            qfp[i].queueFamilyProperties = pQueueFamilyProperties[i];
1117943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        }
1118043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        pqfp = qfp.data();
1118143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    }
1118243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    StateUpdateCommonGetPhysicalDeviceQueueFamilyProperties(pd_state, count, pqfp);
1118343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1118443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1118543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic void PostCallRecordGetPhysicalDeviceQueueFamilyProperties2KHR(PHYSICAL_DEVICE_STATE *pd_state, uint32_t count,
1118643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                     VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
1118743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    StateUpdateCommonGetPhysicalDeviceQueueFamilyProperties(pd_state, count, pQueueFamilyProperties);
1118843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1118943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
11190bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
11191bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                  VkQueueFamilyProperties *pQueueFamilyProperties) {
1119256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
111939a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
1119443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    assert(physical_device_state);
1119543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    bool skip =
1119643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        PreCallValidateGetPhysicalDeviceQueueFamilyProperties(instance_data, physical_device_state, pCount, pQueueFamilyProperties);
1119743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    if (skip) {
1119843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        return;
1119943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    }
1120043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, pCount, pQueueFamilyProperties);
1120143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    PostCallRecordGetPhysicalDeviceQueueFamilyProperties(physical_device_state, *pCount, pQueueFamilyProperties);
1120243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1120343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1120443947a6175e3e942e04d902f4d18928168e2d0dbTobin EhlisVKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceQueueFamilyProperties2KHR(VkPhysicalDevice physicalDevice,
1120543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                      uint32_t *pQueueFamilyPropertyCount,
1120643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                      VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
1120756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
112089a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
1120943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    assert(physical_device_state);
1121043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    bool skip = PreCallValidateGetPhysicalDeviceQueueFamilyProperties2KHR(instance_data, physical_device_state,
1121143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                          pQueueFamilyPropertyCount, pQueueFamilyProperties);
1121243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    if (skip) {
1121343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        return;
11214cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski    }
1121543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties2KHR(physicalDevice, pQueueFamilyPropertyCount,
1121643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                             pQueueFamilyProperties);
1121743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    PostCallRecordGetPhysicalDeviceQueueFamilyProperties2KHR(physical_device_state, *pQueueFamilyPropertyCount,
1121843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                             pQueueFamilyProperties);
11219cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski}
11220cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski
11221bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskitemplate <typename TCreateInfo, typename FPtr>
11222bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic VkResult CreateSurface(VkInstance instance, TCreateInfo const *pCreateInfo, VkAllocationCallbacks const *pAllocator,
11223bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                              VkSurfaceKHR *pSurface, FPtr fptr) {
1122456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
11225747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11226747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    // Call down the call chain:
11227747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    VkResult result = (instance_data->dispatch_table.*fptr)(instance, pCreateInfo, pAllocator, pSurface);
11228747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11229747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    if (result == VK_SUCCESS) {
11230747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        std::unique_lock<std::mutex> lock(global_lock);
11231747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        instance_data->surface_map[*pSurface] = SURFACE_STATE(*pSurface);
11232747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        lock.unlock();
11233747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
11234747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11235747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return result;
11236747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11237747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11238747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR void VKAPI_CALL DestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks *pAllocator) {
11239747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    bool skip_call = false;
1124056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
11241747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
112429a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto surface_state = GetSurfaceState(instance_data, surface);
11243747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11244747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    if (surface_state) {
11245747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        // TODO: track swapchains created from this surface.
11246747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        instance_data->surface_map.erase(surface);
11247747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
11248747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    lock.unlock();
11249747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11250747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    if (!skip_call) {
11251747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        // Call down the call chain:
11252747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        instance_data->dispatch_table.DestroySurfaceKHR(instance, surface, pAllocator);
11253747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
11254747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11255747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
112566f2ed666809272002a31b3b4f8adf6581cb41819Norbert NopperVKAPI_ATTR VkResult VKAPI_CALL CreateDisplayPlaneSurfaceKHR(VkInstance instance, const VkDisplaySurfaceCreateInfoKHR *pCreateInfo,
112576f2ed666809272002a31b3b4f8adf6581cb41819Norbert Nopper                                                            const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
112586f2ed666809272002a31b3b4f8adf6581cb41819Norbert Nopper    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateDisplayPlaneSurfaceKHR);
112596f2ed666809272002a31b3b4f8adf6581cb41819Norbert Nopper}
112606f2ed666809272002a31b3b4f8adf6581cb41819Norbert Nopper
11261747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_ANDROID_KHR
11262747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR *pCreateInfo,
11263747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                       const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
11264747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateAndroidSurfaceKHR);
11265747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11266cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_ANDROID_KHR
11267747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11268747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_MIR_KHR
11269747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateMirSurfaceKHR(VkInstance instance, const VkMirSurfaceCreateInfoKHR *pCreateInfo,
11270747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                   const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
11271747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateMirSurfaceKHR);
11272747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11273cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_MIR_KHR
11274747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11275747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WAYLAND_KHR
11276747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateWaylandSurfaceKHR(VkInstance instance, const VkWaylandSurfaceCreateInfoKHR *pCreateInfo,
11277747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                       const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
11278a9c6cc532ce0ef61d48d1419a96aae51b0e4c64aTobin Ehlis    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateWaylandSurfaceKHR);
11279747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11280cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_WAYLAND_KHR
11281747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11282747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WIN32_KHR
11283747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateWin32SurfaceKHR(VkInstance instance, const VkWin32SurfaceCreateInfoKHR *pCreateInfo,
11284747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                     const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
11285747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateWin32SurfaceKHR);
11286747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11287cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_WIN32_KHR
11288747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11289747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XCB_KHR
11290747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateXcbSurfaceKHR(VkInstance instance, const VkXcbSurfaceCreateInfoKHR *pCreateInfo,
11291747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                   const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
11292747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateXcbSurfaceKHR);
11293747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11294cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_XCB_KHR
11295747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11296747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XLIB_KHR
11297747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateXlibSurfaceKHR(VkInstance instance, const VkXlibSurfaceCreateInfoKHR *pCreateInfo,
11298bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                    const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
11299747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateXlibSurfaceKHR);
11300747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11301cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_XLIB_KHR
11302747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
1130340921785005eb449ec7c18229f0d84c879708b8aChris ForbesVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
1130440921785005eb449ec7c18229f0d84c879708b8aChris Forbes                                                                       VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) {
1130556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    auto instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
1130640921785005eb449ec7c18229f0d84c879708b8aChris Forbes
1130740921785005eb449ec7c18229f0d84c879708b8aChris Forbes    std::unique_lock<std::mutex> lock(global_lock);
113089a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
1130940921785005eb449ec7c18229f0d84c879708b8aChris Forbes    lock.unlock();
1131040921785005eb449ec7c18229f0d84c879708b8aChris Forbes
11311bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result =
11312bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        instance_data->dispatch_table.GetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, pSurfaceCapabilities);
1131340921785005eb449ec7c18229f0d84c879708b8aChris Forbes
1131440921785005eb449ec7c18229f0d84c879708b8aChris Forbes    if (result == VK_SUCCESS) {
1131540921785005eb449ec7c18229f0d84c879708b8aChris Forbes        physical_device_state->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState = QUERY_DETAILS;
1131640921785005eb449ec7c18229f0d84c879708b8aChris Forbes        physical_device_state->surfaceCapabilities = *pSurfaceCapabilities;
1131740921785005eb449ec7c18229f0d84c879708b8aChris Forbes    }
1131840921785005eb449ec7c18229f0d84c879708b8aChris Forbes
1131940921785005eb449ec7c18229f0d84c879708b8aChris Forbes    return result;
1132040921785005eb449ec7c18229f0d84c879708b8aChris Forbes}
1132140921785005eb449ec7c18229f0d84c879708b8aChris Forbes
11322418a8711f3301f3027a900bb45daaf0892f4e644Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex,
11323418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes                                                                  VkSurfaceKHR surface, VkBool32 *pSupported) {
1132456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    auto instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
11325418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
113269a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto surface_state = GetSurfaceState(instance_data, surface);
11327418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    lock.unlock();
11328418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes
11329bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result =
11330bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        instance_data->dispatch_table.GetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, surface, pSupported);
11331418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes
11332418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    if (result == VK_SUCCESS) {
113336569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski        surface_state->gpu_queue_support[{physicalDevice, queueFamilyIndex}] = (*pSupported != 0);
11334418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    }
11335418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes
11336418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    return result;
11337418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes}
11338418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes
113399e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
113409e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                                                                       uint32_t *pPresentModeCount,
113419e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                                                                       VkPresentModeKHR *pPresentModes) {
113429e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    bool skip_call = false;
1134356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    auto instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
113449e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
113459e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    // TODO: this isn't quite right. available modes may differ by surface AND physical device.
113469a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
11347bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto &call_state = physical_device_state->vkGetPhysicalDeviceSurfacePresentModesKHRState;
113489e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
113499e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    if (pPresentModes) {
113509e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        // Compare the preliminary value of *pPresentModeCount with the value this time:
11351bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto prev_mode_count = (uint32_t)physical_device_state->present_modes.size();
113529e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        switch (call_state) {
11353cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case UNCALLED:
113549e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                skip_call |= log_msg(
11355bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
11356cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    reinterpret_cast<uint64_t>(physicalDevice), __LINE__, DEVLIMITS_MUST_QUERY_COUNT, "DL",
11357cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "vkGetPhysicalDeviceSurfacePresentModesKHR() called with non-NULL pPresentModeCount; but no prior positive "
11358cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "value has been seen for pPresentModeCount.");
11359cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
11360cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
11361cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // both query count and query details
11362cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (*pPresentModeCount != prev_mode_count) {
11363cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip_call |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
11364cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
11365cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         reinterpret_cast<uint64_t>(physicalDevice), __LINE__, DEVLIMITS_COUNT_MISMATCH, "DL",
11366cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         "vkGetPhysicalDeviceSurfacePresentModesKHR() called with *pPresentModeCount (%u) that "
11367cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         "differs from the value "
11368cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         "(%u) that was returned when pPresentModes was NULL.",
11369cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                         *pPresentModeCount, prev_mode_count);
11370cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
11371cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
113729e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
113739e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    }
113749e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    lock.unlock();
113759e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
11376cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
113779e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
11378bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result = instance_data->dispatch_table.GetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, pPresentModeCount,
11379bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                        pPresentModes);
113809e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
113819e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
113829e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        lock.lock();
113839e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
113849e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        if (*pPresentModeCount) {
11385cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (call_state < QUERY_COUNT) call_state = QUERY_COUNT;
113869e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            if (*pPresentModeCount > physical_device_state->present_modes.size())
113879e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                physical_device_state->present_modes.resize(*pPresentModeCount);
113889e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
113899e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        if (pPresentModes) {
11390cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (call_state < QUERY_DETAILS) call_state = QUERY_DETAILS;
113919e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            for (uint32_t i = 0; i < *pPresentModeCount; i++) {
113929e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                physical_device_state->present_modes[i] = pPresentModes[i];
113939e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            }
113949e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
113955faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    }
113965faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
113975faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    return result;
113985faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes}
113995faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
114005faa662f6859b01c72d79027abde363d5f10dcd7Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
114015faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                                                                  uint32_t *pSurfaceFormatCount,
114025faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                                                                  VkSurfaceFormatKHR *pSurfaceFormats) {
114035faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    bool skip_call = false;
1140456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    auto instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
114055faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
114069a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
11407bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto &call_state = physical_device_state->vkGetPhysicalDeviceSurfaceFormatsKHRState;
114085faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
114095faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    if (pSurfaceFormats) {
11410bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto prev_format_count = (uint32_t)physical_device_state->surface_formats.size();
114115faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
114125faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        switch (call_state) {
11413cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case UNCALLED:
11414cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // Since we haven't recorded a preliminary value of *pSurfaceFormatCount, that likely means that the application
11415cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // didn't
11416cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // previously call this function with a NULL value of pSurfaceFormats:
114175faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                skip_call |= log_msg(
11418bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
11419cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    reinterpret_cast<uint64_t>(physicalDevice), __LINE__, DEVLIMITS_MUST_QUERY_COUNT, "DL",
11420cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "vkGetPhysicalDeviceSurfaceFormatsKHR() called with non-NULL pSurfaceFormatCount; but no prior positive "
11421cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "value has been seen for pSurfaceFormats.");
11422cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
11423cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
11424cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (prev_format_count != *pSurfaceFormatCount) {
11425cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    skip_call |= log_msg(
11426cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
11427cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, reinterpret_cast<uint64_t>(physicalDevice), __LINE__,
11428cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        DEVLIMITS_COUNT_MISMATCH, "DL",
11429cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "vkGetPhysicalDeviceSurfaceFormatsKHR() called with non-NULL pSurfaceFormatCount, and with pSurfaceFormats "
11430cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "set "
11431cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "to "
11432cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "a value (%u) that is greater than the value (%u) that was returned when pSurfaceFormatCount was NULL.",
11433cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        *pSurfaceFormatCount, prev_format_count);
11434cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
11435cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
114369e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
114379e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    }
114385faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    lock.unlock();
114395faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
11440cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip_call) return VK_ERROR_VALIDATION_FAILED_EXT;
114419e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
114425faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    // Call down the call chain:
114435faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    auto result = instance_data->dispatch_table.GetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, pSurfaceFormatCount,
114445faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                                                                                   pSurfaceFormats);
114455faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
114465faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
114475faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        lock.lock();
114485faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
114495faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        if (*pSurfaceFormatCount) {
11450cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (call_state < QUERY_COUNT) call_state = QUERY_COUNT;
114515faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            if (*pSurfaceFormatCount > physical_device_state->surface_formats.size())
114525faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                physical_device_state->surface_formats.resize(*pSurfaceFormatCount);
114535faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        }
114545faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        if (pSurfaceFormats) {
11455cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (call_state < QUERY_DETAILS) call_state = QUERY_DETAILS;
114565faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            for (uint32_t i = 0; i < *pSurfaceFormatCount; i++) {
114575faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                physical_device_state->surface_formats[i] = pSurfaceFormats[i];
114585faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            }
114595faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        }
114605faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    }
114619e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    return result;
114629e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes}
114639e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
11464bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateDebugReportCallbackEXT(VkInstance instance,
11465bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                            const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
11466bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                            const VkAllocationCallbacks *pAllocator,
11467bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                            VkDebugReportCallbackEXT *pMsgCallback) {
1146856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
114699172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    VkResult res = instance_data->dispatch_table.CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
114705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == res) {
11471b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
114728860b85a52096f9f9b28616bc37feed505497a54Chris Forbes        res = layer_create_msg_callback(instance_data->report_data, false, pCreateInfo, pAllocator, pMsgCallback);
114735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
114745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return res;
114755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
114765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11477bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT msgCallback,
1147889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                         const VkAllocationCallbacks *pAllocator) {
1147956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
114809172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    instance_data->dispatch_table.DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);
11481b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::lock_guard<std::mutex> lock(global_lock);
114828860b85a52096f9f9b28616bc37feed505497a54Chris Forbes    layer_destroy_msg_callback(instance_data->report_data, msgCallback, pAllocator);
114835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
114845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11485bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags,
11486bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 VkDebugReportObjectTypeEXT objType, uint64_t object, size_t location,
11487bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
1148856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
114899172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    instance_data->dispatch_table.DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, pMsg);
114905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
114915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11492bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties) {
11493a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return util_GetLayerProperties(1, &global_layer, pCount, pProperties);
11494a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu}
11495a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu
11496bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
11497bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                              VkLayerProperties *pProperties) {
11498a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return util_GetLayerProperties(1, &global_layer, pCount, pProperties);
11499a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu}
11500a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu
11501bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
11502bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                    VkExtensionProperties *pProperties) {
11503a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    if (pLayerName && !strcmp(pLayerName, global_layer.layerName))
11504a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu        return util_GetExtensionProperties(1, instance_extensions, pCount, pProperties);
11505a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu
11506a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return VK_ERROR_LAYER_NOT_PRESENT;
11507a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu}
11508a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu
11509bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char *pLayerName,
11510bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                  uint32_t *pCount, VkExtensionProperties *pProperties) {
11511cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (pLayerName && !strcmp(pLayerName, global_layer.layerName)) return util_GetExtensionProperties(0, NULL, pCount, pProperties);
11512a8f4a23b1e9c068717eda47cc583a93f447c77e3Chia-I Wu
11513a8f4a23b1e9c068717eda47cc583a93f447c77e3Chia-I Wu    assert(physicalDevice);
11514a8f4a23b1e9c068717eda47cc583a93f447c77e3Chia-I Wu
1151556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
115169172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    return instance_data->dispatch_table.EnumerateDeviceExtensionProperties(physicalDevice, NULL, pCount, pProperties);
1151708939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu}
1151808939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu
11519582b6ed09649188d55ed3b6237352caf9f3384a9Mike WeiblenVKAPI_ATTR VkResult VKAPI_CALL EnumeratePhysicalDeviceGroupsKHX(
11520582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen    VkInstance instance, uint32_t *pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupPropertiesKHX *pPhysicalDeviceGroupProperties) {
11521582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen    bool skip_call = false;
11522582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
11523582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen
11524582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen    if (instance_data) {
11525582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        // For this instance, flag when EnumeratePhysicalDeviceGroupsKHX goes to QUERY_COUNT and then QUERY_DETAILS.
11526582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        if (NULL == pPhysicalDeviceGroupProperties) {
11527582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            instance_data->vkEnumeratePhysicalDeviceGroupsState = QUERY_COUNT;
11528582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        } else {
11529582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            if (UNCALLED == instance_data->vkEnumeratePhysicalDeviceGroupsState) {
11530582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                // Flag warning here. You can call this without having queried the count, but it may not be
11531582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                // robust on platforms with multiple physical devices.
11532582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                skip_call |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
11533582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                    VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, 0, __LINE__, DEVLIMITS_MISSING_QUERY_COUNT, "DL",
11534582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                    "Call sequence has vkEnumeratePhysicalDeviceGroupsKHX() w/ non-NULL "
11535582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                    "pPhysicalDeviceGroupProperties. You should first "
11536582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                    "call vkEnumeratePhysicalDeviceGroupsKHX() w/ NULL pPhysicalDeviceGroupProperties to query "
11537582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                    "pPhysicalDeviceGroupCount.");
11538582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            } // TODO : Could also flag a warning if re-calling this function in QUERY_DETAILS state
11539582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            else if (instance_data->physical_device_groups_count != *pPhysicalDeviceGroupCount) {
11540582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                // Having actual count match count from app is not a requirement, so this can be a warning
11541582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                skip_call |=
11542582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                    log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
11543582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                        VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVLIMITS_COUNT_MISMATCH, "DL",
11544582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                        "Call to vkEnumeratePhysicalDeviceGroupsKHX() w/ pPhysicalDeviceGroupCount value %u, but actual count "
11545582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                        "supported by this instance is %u.",
11546582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                        *pPhysicalDeviceGroupCount, instance_data->physical_device_groups_count);
11547582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            }
11548582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            instance_data->vkEnumeratePhysicalDeviceGroupsState = QUERY_DETAILS;
11549582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        }
11550582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        if (skip_call) {
11551582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            return VK_ERROR_VALIDATION_FAILED_EXT;
11552582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        }
11553582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        VkResult result = instance_data->dispatch_table.EnumeratePhysicalDeviceGroupsKHX(instance, pPhysicalDeviceGroupCount,
11554582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            pPhysicalDeviceGroupProperties);
11555582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        if (NULL == pPhysicalDeviceGroupProperties) {
11556582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            instance_data->physical_device_groups_count = *pPhysicalDeviceGroupCount;
11557582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        } else if (result == VK_SUCCESS) { // Save physical devices
11558582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            for (uint32_t i = 0; i < *pPhysicalDeviceGroupCount; i++) {
11559582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                for (uint32_t j = 0; j < pPhysicalDeviceGroupProperties[i].physicalDeviceCount; j++) {
11560582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                    VkPhysicalDevice cur_phys_dev = pPhysicalDeviceGroupProperties[i].physicalDevices[j];
11561582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                    auto &phys_device_state = instance_data->physical_device_map[cur_phys_dev];
11562582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                    phys_device_state.phys_device = cur_phys_dev;
11563582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                    // Init actual features for each physical device
11564582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                    instance_data->dispatch_table.GetPhysicalDeviceFeatures(cur_phys_dev, &phys_device_state.features);
11565582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                }
11566582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            }
11567582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        }
11568582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        return result;
11569582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen    } else {
11570582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, 0, __LINE__,
11571582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            DEVLIMITS_INVALID_INSTANCE, "DL",
11572582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            "Invalid instance (0x%" PRIxLEAST64 ") passed into vkEnumeratePhysicalDeviceGroupsKHX().", (uint64_t)instance);
11573582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen    }
11574582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen    return VK_ERROR_VALIDATION_FAILED_EXT;
11575582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen}
11576582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen
115776246f8feba03ddc787c31b3daa6a50d4ef01024fMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateDescriptorUpdateTemplateKHR(VkDevice device,
115786246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                                 const VkDescriptorUpdateTemplateCreateInfoKHR *pCreateInfo,
115796246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                                 const VkAllocationCallbacks *pAllocator,
115806246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                                 VkDescriptorUpdateTemplateKHR *pDescriptorUpdateTemplate) {
115816246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
11582a538cd4fff983b172362b0bba58f984124481a1cMark Lobodzinski    VkResult result =
11583a538cd4fff983b172362b0bba58f984124481a1cMark Lobodzinski        dev_data->dispatch_table.CreateDescriptorUpdateTemplateKHR(device, pCreateInfo, pAllocator, pDescriptorUpdateTemplate);
115846246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    if (VK_SUCCESS == result) {
115856246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        std::lock_guard<std::mutex> lock(global_lock);
115866246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        // Shadow template createInfo for later updates
11587a538cd4fff983b172362b0bba58f984124481a1cMark Lobodzinski        safe_VkDescriptorUpdateTemplateCreateInfoKHR *local_create_info =
11588a538cd4fff983b172362b0bba58f984124481a1cMark Lobodzinski            new safe_VkDescriptorUpdateTemplateCreateInfoKHR(pCreateInfo);
115896246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        std::unique_ptr<TEMPLATE_STATE> template_state(new TEMPLATE_STATE(*pDescriptorUpdateTemplate, local_create_info));
115906246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        dev_data->desc_template_map[*pDescriptorUpdateTemplate] = std::move(template_state);
115916246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    }
115926246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    return result;
115936246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski}
115946246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski
115956246f8feba03ddc787c31b3daa6a50d4ef01024fMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyDescriptorUpdateTemplateKHR(VkDevice device,
115966246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                              VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
115976246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                              const VkAllocationCallbacks *pAllocator) {
115986246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
115996246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    std::unique_lock<std::mutex> lock(global_lock);
116006246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    dev_data->desc_template_map.erase(descriptorUpdateTemplate);
116016246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    lock.unlock();
116026246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    dev_data->dispatch_table.DestroyDescriptorUpdateTemplateKHR(device, descriptorUpdateTemplate, pAllocator);
116036246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski}
116046246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski
1160525f3712aed1cebdcb7c92eb25c5f1cc6e5986ac4Mark Lobodzinski// PostCallRecord* handles recording state updates following call down chain to UpdateDescriptorSetsWithTemplate()
1160625f3712aed1cebdcb7c92eb25c5f1cc6e5986ac4Mark Lobodzinskistatic void PostCallRecordUpdateDescriptorSetWithTemplateKHR(layer_data *device_data, VkDescriptorSet descriptorSet,
1160725f3712aed1cebdcb7c92eb25c5f1cc6e5986ac4Mark Lobodzinski                                                             VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
1160825f3712aed1cebdcb7c92eb25c5f1cc6e5986ac4Mark Lobodzinski                                                             const void *pData) {
1160967fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski    auto const template_map_entry = device_data->desc_template_map.find(descriptorUpdateTemplate);
1161067fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski    if (template_map_entry == device_data->desc_template_map.end()) {
1161167fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski        assert(0);
1161267fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski    }
1161367fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski
1161425f3712aed1cebdcb7c92eb25c5f1cc6e5986ac4Mark Lobodzinski    cvdescriptorset::PerformUpdateDescriptorSetsWithTemplateKHR(device_data, descriptorSet, template_map_entry->second, pData);
1161567fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski}
1161667fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski
116176246f8feba03ddc787c31b3daa6a50d4ef01024fMark LobodzinskiVKAPI_ATTR void VKAPI_CALL UpdateDescriptorSetWithTemplateKHR(VkDevice device, VkDescriptorSet descriptorSet,
116186246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                              VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
116196246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                              const void *pData) {
1162067fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
1162167fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski    device_data->dispatch_table.UpdateDescriptorSetWithTemplateKHR(device, descriptorSet, descriptorUpdateTemplate, pData);
1162267fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski
1162367fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski    PostCallRecordUpdateDescriptorSetWithTemplateKHR(device_data, descriptorSet, descriptorUpdateTemplate, pData);
116246246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski}
116256246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski
116266246f8feba03ddc787c31b3daa6a50d4ef01024fMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdPushDescriptorSetWithTemplateKHR(VkCommandBuffer commandBuffer,
116276246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                               VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
116286246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                               VkPipelineLayout layout, uint32_t set, const void *pData) {
116296246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
116306246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    dev_data->dispatch_table.CmdPushDescriptorSetWithTemplateKHR(commandBuffer, descriptorUpdateTemplate, layout, set, pData);
116316246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski}
116326246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski
11633bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_core_instance_command(const char *name);
116347ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu
11635bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_core_device_command(const char *name);
1163680be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu
116376246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinskistatic PFN_vkVoidFunction intercept_device_extension_command(const char *name, VkDevice device);
116386246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski
11639bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_khr_swapchain_command(const char *name, VkDevice dev);
1164009a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu
11641bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_khr_surface_command(const char *name, VkInstance instance);
11642747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11643582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblenstatic PFN_vkVoidFunction
11644582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblenintercept_extension_instance_commands(const char *name, VkInstance instance);
11645b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
1164689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice dev, const char *funcName) {
1164780be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    assert(dev);
116485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
116496246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    PFN_vkVoidFunction proc = intercept_core_device_command(funcName);
116506246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    if (!proc) proc = intercept_device_extension_command(funcName, dev);
116516246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    if (!proc) proc = intercept_khr_swapchain_command(funcName, dev);
11652cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (proc) return proc;
1165309a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu
1165456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(dev), layer_data_map);
116554a0754042cf090e131e9e769d8a3633c228625beChris Forbes    auto &table = dev_data->dispatch_table;
11656cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!table.GetDeviceProcAddr) return nullptr;
116574a0754042cf090e131e9e769d8a3633c228625beChris Forbes    return table.GetDeviceProcAddr(dev, funcName);
116585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
116595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1166089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetInstanceProcAddr(VkInstance instance, const char *funcName) {
116617ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    PFN_vkVoidFunction proc = intercept_core_instance_command(funcName);
11662cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!proc) proc = intercept_core_device_command(funcName);
11663cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!proc) proc = intercept_khr_swapchain_command(funcName, VK_NULL_HANDLE);
11664cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!proc) proc = intercept_khr_surface_command(funcName, instance);
11665cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (proc) return proc;
116665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
116677ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    assert(instance);
116685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1166956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
116708860b85a52096f9f9b28616bc37feed505497a54Chris Forbes    proc = debug_report_get_instance_proc_addr(instance_data->report_data, funcName);
11671cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (proc) return proc;
116725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11673b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    proc = intercept_extension_instance_commands(funcName, instance);
11674cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (proc) return proc;
11675b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
116764a0754042cf090e131e9e769d8a3633c228625beChris Forbes    auto &table = instance_data->dispatch_table;
11677cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!table.GetInstanceProcAddr) return nullptr;
116784a0754042cf090e131e9e769d8a3633c228625beChris Forbes    return table.GetInstanceProcAddr(instance, funcName);
116795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
1168008939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu
11681b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark YoungVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
11682b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    assert(instance);
11683b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
1168456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
11685b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11686b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    auto &table = instance_data->dispatch_table;
11687cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!table.GetPhysicalDeviceProcAddr) return nullptr;
11688b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    return table.GetPhysicalDeviceProcAddr(instance, funcName);
11689b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young}
11690b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11691bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_core_instance_command(const char *name) {
116927ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    static const struct {
116937ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu        const char *name;
116947ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu        PFN_vkVoidFunction proc;
116957ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    } core_instance_commands[] = {
11696bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkGetInstanceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetInstanceProcAddr)},
11697bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vk_layerGetPhysicalDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceProcAddr)},
11698bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkGetDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceProcAddr)},
11699bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkCreateInstance", reinterpret_cast<PFN_vkVoidFunction>(CreateInstance)},
11700bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkCreateDevice", reinterpret_cast<PFN_vkVoidFunction>(CreateDevice)},
11701bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkEnumeratePhysicalDevices", reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDevices)},
11702bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkGetPhysicalDeviceQueueFamilyProperties", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceQueueFamilyProperties)},
11703bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkDestroyInstance", reinterpret_cast<PFN_vkVoidFunction>(DestroyInstance)},
11704bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkEnumerateInstanceLayerProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceLayerProperties)},
11705bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkEnumerateDeviceLayerProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateDeviceLayerProperties)},
11706bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkEnumerateInstanceExtensionProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceExtensionProperties)},
11707bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkEnumerateDeviceExtensionProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateDeviceExtensionProperties)},
117087ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    };
117097ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu
117107ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    for (size_t i = 0; i < ARRAY_SIZE(core_instance_commands); i++) {
11711cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!strcmp(core_instance_commands[i].name, name)) return core_instance_commands[i].proc;
117127ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    }
117137ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu
117147ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu    return nullptr;
117157ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu}
117167ed76a2d9a619f963e7a1afb13e9913fbc09dc63Chia-I Wu
11717bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_core_device_command(const char *name) {
1171880be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    static const struct {
1171980be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu        const char *name;
1172080be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu        PFN_vkVoidFunction proc;
1172180be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    } core_device_commands[] = {
11722593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkGetDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceProcAddr)},
11723593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkQueueSubmit", reinterpret_cast<PFN_vkVoidFunction>(QueueSubmit)},
11724593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkWaitForFences", reinterpret_cast<PFN_vkVoidFunction>(WaitForFences)},
11725593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkGetFenceStatus", reinterpret_cast<PFN_vkVoidFunction>(GetFenceStatus)},
11726593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkQueueWaitIdle", reinterpret_cast<PFN_vkVoidFunction>(QueueWaitIdle)},
11727593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDeviceWaitIdle", reinterpret_cast<PFN_vkVoidFunction>(DeviceWaitIdle)},
11728593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkGetDeviceQueue", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceQueue)},
11729593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyInstance", reinterpret_cast<PFN_vkVoidFunction>(DestroyInstance)},
11730593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyDevice", reinterpret_cast<PFN_vkVoidFunction>(DestroyDevice)},
11731593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyFence", reinterpret_cast<PFN_vkVoidFunction>(DestroyFence)},
11732593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkResetFences", reinterpret_cast<PFN_vkVoidFunction>(ResetFences)},
11733593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroySemaphore", reinterpret_cast<PFN_vkVoidFunction>(DestroySemaphore)},
11734593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyEvent", reinterpret_cast<PFN_vkVoidFunction>(DestroyEvent)},
11735593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyQueryPool", reinterpret_cast<PFN_vkVoidFunction>(DestroyQueryPool)},
11736593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyBuffer", reinterpret_cast<PFN_vkVoidFunction>(DestroyBuffer)},
11737593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyBufferView", reinterpret_cast<PFN_vkVoidFunction>(DestroyBufferView)},
11738593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyImage", reinterpret_cast<PFN_vkVoidFunction>(DestroyImage)},
11739593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyImageView", reinterpret_cast<PFN_vkVoidFunction>(DestroyImageView)},
11740593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyShaderModule", reinterpret_cast<PFN_vkVoidFunction>(DestroyShaderModule)},
11741593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyPipeline", reinterpret_cast<PFN_vkVoidFunction>(DestroyPipeline)},
11742593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyPipelineLayout", reinterpret_cast<PFN_vkVoidFunction>(DestroyPipelineLayout)},
11743593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroySampler", reinterpret_cast<PFN_vkVoidFunction>(DestroySampler)},
11744593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyDescriptorSetLayout", reinterpret_cast<PFN_vkVoidFunction>(DestroyDescriptorSetLayout)},
11745593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(DestroyDescriptorPool)},
11746593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyFramebuffer", reinterpret_cast<PFN_vkVoidFunction>(DestroyFramebuffer)},
11747593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyRenderPass", reinterpret_cast<PFN_vkVoidFunction>(DestroyRenderPass)},
11748593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateBuffer", reinterpret_cast<PFN_vkVoidFunction>(CreateBuffer)},
11749593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateBufferView", reinterpret_cast<PFN_vkVoidFunction>(CreateBufferView)},
11750593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateImage", reinterpret_cast<PFN_vkVoidFunction>(CreateImage)},
11751593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateImageView", reinterpret_cast<PFN_vkVoidFunction>(CreateImageView)},
11752593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateFence", reinterpret_cast<PFN_vkVoidFunction>(CreateFence)},
11753593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreatePipelineCache", reinterpret_cast<PFN_vkVoidFunction>(CreatePipelineCache)},
11754593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyPipelineCache", reinterpret_cast<PFN_vkVoidFunction>(DestroyPipelineCache)},
11755593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkGetPipelineCacheData", reinterpret_cast<PFN_vkVoidFunction>(GetPipelineCacheData)},
11756593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkMergePipelineCaches", reinterpret_cast<PFN_vkVoidFunction>(MergePipelineCaches)},
11757593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateGraphicsPipelines", reinterpret_cast<PFN_vkVoidFunction>(CreateGraphicsPipelines)},
11758593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateComputePipelines", reinterpret_cast<PFN_vkVoidFunction>(CreateComputePipelines)},
11759593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateSampler", reinterpret_cast<PFN_vkVoidFunction>(CreateSampler)},
11760593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateDescriptorSetLayout", reinterpret_cast<PFN_vkVoidFunction>(CreateDescriptorSetLayout)},
11761593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreatePipelineLayout", reinterpret_cast<PFN_vkVoidFunction>(CreatePipelineLayout)},
11762593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(CreateDescriptorPool)},
11763593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkResetDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(ResetDescriptorPool)},
11764593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkAllocateDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(AllocateDescriptorSets)},
11765593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkFreeDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(FreeDescriptorSets)},
11766593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkUpdateDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(UpdateDescriptorSets)},
11767593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateCommandPool", reinterpret_cast<PFN_vkVoidFunction>(CreateCommandPool)},
11768593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkDestroyCommandPool", reinterpret_cast<PFN_vkVoidFunction>(DestroyCommandPool)},
11769593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkResetCommandPool", reinterpret_cast<PFN_vkVoidFunction>(ResetCommandPool)},
11770593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateQueryPool", reinterpret_cast<PFN_vkVoidFunction>(CreateQueryPool)},
11771593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkAllocateCommandBuffers", reinterpret_cast<PFN_vkVoidFunction>(AllocateCommandBuffers)},
11772593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkFreeCommandBuffers", reinterpret_cast<PFN_vkVoidFunction>(FreeCommandBuffers)},
11773593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkBeginCommandBuffer", reinterpret_cast<PFN_vkVoidFunction>(BeginCommandBuffer)},
11774593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkEndCommandBuffer", reinterpret_cast<PFN_vkVoidFunction>(EndCommandBuffer)},
11775593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkResetCommandBuffer", reinterpret_cast<PFN_vkVoidFunction>(ResetCommandBuffer)},
11776593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdBindPipeline", reinterpret_cast<PFN_vkVoidFunction>(CmdBindPipeline)},
11777593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetViewport", reinterpret_cast<PFN_vkVoidFunction>(CmdSetViewport)},
11778593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetScissor", reinterpret_cast<PFN_vkVoidFunction>(CmdSetScissor)},
11779593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetLineWidth", reinterpret_cast<PFN_vkVoidFunction>(CmdSetLineWidth)},
11780593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetDepthBias", reinterpret_cast<PFN_vkVoidFunction>(CmdSetDepthBias)},
11781593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetBlendConstants", reinterpret_cast<PFN_vkVoidFunction>(CmdSetBlendConstants)},
11782593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetDepthBounds", reinterpret_cast<PFN_vkVoidFunction>(CmdSetDepthBounds)},
11783593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetStencilCompareMask", reinterpret_cast<PFN_vkVoidFunction>(CmdSetStencilCompareMask)},
11784593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetStencilWriteMask", reinterpret_cast<PFN_vkVoidFunction>(CmdSetStencilWriteMask)},
11785593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetStencilReference", reinterpret_cast<PFN_vkVoidFunction>(CmdSetStencilReference)},
11786593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdBindDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(CmdBindDescriptorSets)},
11787593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdBindVertexBuffers", reinterpret_cast<PFN_vkVoidFunction>(CmdBindVertexBuffers)},
11788593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdBindIndexBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdBindIndexBuffer)},
11789593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdDraw", reinterpret_cast<PFN_vkVoidFunction>(CmdDraw)},
11790593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdDrawIndexed", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndexed)},
11791593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdDrawIndirect", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndirect)},
11792593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdDrawIndexedIndirect", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndexedIndirect)},
11793593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdDispatch", reinterpret_cast<PFN_vkVoidFunction>(CmdDispatch)},
11794593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdDispatchIndirect", reinterpret_cast<PFN_vkVoidFunction>(CmdDispatchIndirect)},
11795593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdCopyBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyBuffer)},
11796593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdCopyImage", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyImage)},
11797593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdBlitImage", reinterpret_cast<PFN_vkVoidFunction>(CmdBlitImage)},
11798593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdCopyBufferToImage", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyBufferToImage)},
11799593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdCopyImageToBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyImageToBuffer)},
11800593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdUpdateBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdUpdateBuffer)},
11801593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdFillBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdFillBuffer)},
11802593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdClearColorImage", reinterpret_cast<PFN_vkVoidFunction>(CmdClearColorImage)},
11803593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdClearDepthStencilImage", reinterpret_cast<PFN_vkVoidFunction>(CmdClearDepthStencilImage)},
11804593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdClearAttachments", reinterpret_cast<PFN_vkVoidFunction>(CmdClearAttachments)},
11805593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdResolveImage", reinterpret_cast<PFN_vkVoidFunction>(CmdResolveImage)},
11806b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski        {"vkGetImageSubresourceLayout", reinterpret_cast<PFN_vkVoidFunction>(GetImageSubresourceLayout) },
11807593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdSetEvent", reinterpret_cast<PFN_vkVoidFunction>(CmdSetEvent)},
11808593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdResetEvent", reinterpret_cast<PFN_vkVoidFunction>(CmdResetEvent)},
11809593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdWaitEvents", reinterpret_cast<PFN_vkVoidFunction>(CmdWaitEvents)},
11810593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdPipelineBarrier", reinterpret_cast<PFN_vkVoidFunction>(CmdPipelineBarrier)},
11811593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdBeginQuery", reinterpret_cast<PFN_vkVoidFunction>(CmdBeginQuery)},
11812593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdEndQuery", reinterpret_cast<PFN_vkVoidFunction>(CmdEndQuery)},
11813593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdResetQueryPool", reinterpret_cast<PFN_vkVoidFunction>(CmdResetQueryPool)},
11814593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdCopyQueryPoolResults", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyQueryPoolResults)},
11815593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdPushConstants", reinterpret_cast<PFN_vkVoidFunction>(CmdPushConstants)},
11816593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdWriteTimestamp", reinterpret_cast<PFN_vkVoidFunction>(CmdWriteTimestamp)},
11817593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateFramebuffer", reinterpret_cast<PFN_vkVoidFunction>(CreateFramebuffer)},
11818593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateShaderModule", reinterpret_cast<PFN_vkVoidFunction>(CreateShaderModule)},
11819593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CreateRenderPass)},
11820593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdBeginRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CmdBeginRenderPass)},
11821593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdNextSubpass", reinterpret_cast<PFN_vkVoidFunction>(CmdNextSubpass)},
11822593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdEndRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CmdEndRenderPass)},
11823593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCmdExecuteCommands", reinterpret_cast<PFN_vkVoidFunction>(CmdExecuteCommands)},
11824593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkSetEvent", reinterpret_cast<PFN_vkVoidFunction>(SetEvent)},
11825593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkMapMemory", reinterpret_cast<PFN_vkVoidFunction>(MapMemory)},
11826593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkUnmapMemory", reinterpret_cast<PFN_vkVoidFunction>(UnmapMemory)},
11827593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkFlushMappedMemoryRanges", reinterpret_cast<PFN_vkVoidFunction>(FlushMappedMemoryRanges)},
11828593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkInvalidateMappedMemoryRanges", reinterpret_cast<PFN_vkVoidFunction>(InvalidateMappedMemoryRanges)},
11829593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkAllocateMemory", reinterpret_cast<PFN_vkVoidFunction>(AllocateMemory)},
11830593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkFreeMemory", reinterpret_cast<PFN_vkVoidFunction>(FreeMemory)},
11831593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkBindBufferMemory", reinterpret_cast<PFN_vkVoidFunction>(BindBufferMemory)},
11832593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkGetBufferMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(GetBufferMemoryRequirements)},
11833593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkGetImageMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(GetImageMemoryRequirements)},
11834593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkGetQueryPoolResults", reinterpret_cast<PFN_vkVoidFunction>(GetQueryPoolResults)},
11835593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkBindImageMemory", reinterpret_cast<PFN_vkVoidFunction>(BindImageMemory)},
11836593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkQueueBindSparse", reinterpret_cast<PFN_vkVoidFunction>(QueueBindSparse)},
11837593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateSemaphore", reinterpret_cast<PFN_vkVoidFunction>(CreateSemaphore)},
11838593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis        {"vkCreateEvent", reinterpret_cast<PFN_vkVoidFunction>(CreateEvent)},
1183980be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    };
1184080be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu
1184180be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    for (size_t i = 0; i < ARRAY_SIZE(core_device_commands); i++) {
11842cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!strcmp(core_device_commands[i].name, name)) return core_device_commands[i].proc;
118436246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    }
118446246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski
118456246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    return nullptr;
118466246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski}
118476246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski
118486246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinskistatic PFN_vkVoidFunction intercept_device_extension_command(const char *name, VkDevice device) {
118496246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
118506246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski
118516246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    const struct {
118526246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        const char *name;
118536246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        PFN_vkVoidFunction proc;
118546246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        bool enabled;
118556246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    } device_extension_commands[] = {
118566246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        {"vkCreateDescriptorUpdateTemplateKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateDescriptorUpdateTemplateKHR),
118576246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski         device_data->device_extensions.khr_descriptor_update_template_enabled},
118586246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        {"vkDestroyDescriptorUpdateTemplateKHR", reinterpret_cast<PFN_vkVoidFunction>(DestroyDescriptorUpdateTemplateKHR),
118596246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski         device_data->device_extensions.khr_descriptor_update_template_enabled},
118606246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        {"vkUpdateDescriptorSetWithTemplateKHR", reinterpret_cast<PFN_vkVoidFunction>(UpdateDescriptorSetWithTemplateKHR),
118616246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski         device_data->device_extensions.khr_descriptor_update_template_enabled},
118626246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        {"vkCmdPushDescriptorSetWithTemplateKHR", reinterpret_cast<PFN_vkVoidFunction>(CmdPushDescriptorSetWithTemplateKHR),
118636246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski         device_data->device_extensions.khr_descriptor_update_template_enabled},
118646246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    };
118656246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski
118666246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    if (!device_data || !device_data->device_extensions.khr_descriptor_update_template_enabled) return nullptr;
118676246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski
118686246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    for (size_t i = 0; i < ARRAY_SIZE(device_extension_commands); i++) {
118696246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        if (!strcmp(device_extension_commands[i].name, name) && device_extension_commands[i].enabled)
118706246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski            return device_extension_commands[i].proc;
1187180be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    }
1187280be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu
1187380be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu    return nullptr;
1187480be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu}
1187580be5ddd2f71eae65d790fe63d1e5b1e1f4daa42Chia-I Wu
11876bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_khr_swapchain_command(const char *name, VkDevice dev) {
1187709a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu    static const struct {
1187809a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu        const char *name;
1187909a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu        PFN_vkVoidFunction proc;
1188009a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu    } khr_swapchain_commands[] = {
11881bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkCreateSwapchainKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateSwapchainKHR)},
11882bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkDestroySwapchainKHR", reinterpret_cast<PFN_vkVoidFunction>(DestroySwapchainKHR)},
11883bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkGetSwapchainImagesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetSwapchainImagesKHR)},
11884bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkAcquireNextImageKHR", reinterpret_cast<PFN_vkVoidFunction>(AcquireNextImageKHR)},
11885bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkQueuePresentKHR", reinterpret_cast<PFN_vkVoidFunction>(QueuePresentKHR)},
1188609a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu    };
11887c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young    layer_data *dev_data = nullptr;
1188809a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu
118893f6f8132355ebdae2736b31fc20de2ac60a70310Chia-I Wu    if (dev) {
1189056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        dev_data = GetLayerDataPtr(get_dispatch_key(dev), layer_data_map);
11891cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!dev_data->device_extensions.wsi_enabled) return nullptr;
118923f6f8132355ebdae2736b31fc20de2ac60a70310Chia-I Wu    }
1189309a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu
1189409a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu    for (size_t i = 0; i < ARRAY_SIZE(khr_swapchain_commands); i++) {
11895cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!strcmp(khr_swapchain_commands[i].name, name)) return khr_swapchain_commands[i].proc;
1189609a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu    }
1189709a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu
11898c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young    if (dev_data) {
11899cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!dev_data->device_extensions.wsi_display_swapchain_enabled) return nullptr;
11900c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young    }
11901c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young
11902cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!strcmp("vkCreateSharedSwapchainsKHR", name)) return reinterpret_cast<PFN_vkVoidFunction>(CreateSharedSwapchainsKHR);
11903c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young
1190409a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu    return nullptr;
11905747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11906747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11907bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic PFN_vkVoidFunction intercept_khr_surface_command(const char *name, VkInstance instance) {
11908747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    static const struct {
11909747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        const char *name;
11910747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        PFN_vkVoidFunction proc;
11911747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        bool instance_layer_data::*enable;
11912747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    } khr_surface_commands[] = {
11913747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_ANDROID_KHR
11914747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        {"vkCreateAndroidSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateAndroidSurfaceKHR),
11915bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::androidSurfaceExtensionEnabled},
11916cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_ANDROID_KHR
11917747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_MIR_KHR
11918747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        {"vkCreateMirSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateMirSurfaceKHR),
11919bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::mirSurfaceExtensionEnabled},
11920cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_MIR_KHR
11921747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WAYLAND_KHR
11922747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        {"vkCreateWaylandSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateWaylandSurfaceKHR),
11923bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::waylandSurfaceExtensionEnabled},
11924cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_WAYLAND_KHR
11925747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WIN32_KHR
11926747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        {"vkCreateWin32SurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateWin32SurfaceKHR),
11927bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::win32SurfaceExtensionEnabled},
11928cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_WIN32_KHR
11929747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XCB_KHR
11930747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        {"vkCreateXcbSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateXcbSurfaceKHR),
11931bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::xcbSurfaceExtensionEnabled},
11932cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_XCB_KHR
11933747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XLIB_KHR
11934747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        {"vkCreateXlibSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateXlibSurfaceKHR),
11935bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::xlibSurfaceExtensionEnabled},
11936cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_XLIB_KHR
11937bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        {"vkCreateDisplayPlaneSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateDisplayPlaneSurfaceKHR),
11938bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::displayExtensionEnabled},
11939747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        {"vkDestroySurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(DestroySurfaceKHR),
11940bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::surfaceExtensionEnabled},
1194140921785005eb449ec7c18229f0d84c879708b8aChris Forbes        {"vkGetPhysicalDeviceSurfaceCapabilitiesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfaceCapabilitiesKHR),
11942bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::surfaceExtensionEnabled},
11943418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes        {"vkGetPhysicalDeviceSurfaceSupportKHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfaceSupportKHR),
11944bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::surfaceExtensionEnabled},
119459e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        {"vkGetPhysicalDeviceSurfacePresentModesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfacePresentModesKHR),
11946bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::surfaceExtensionEnabled},
119475faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        {"vkGetPhysicalDeviceSurfaceFormatsKHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfaceFormatsKHR),
11948bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski         &instance_layer_data::surfaceExtensionEnabled},
11949747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    };
11950747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11951747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    instance_layer_data *instance_data = nullptr;
11952747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    if (instance) {
1195356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
11954747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
11955747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11956747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    for (size_t i = 0; i < ARRAY_SIZE(khr_surface_commands); i++) {
11957747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        if (!strcmp(khr_surface_commands[i].name, name)) {
11958cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (instance_data && !(instance_data->*(khr_surface_commands[i].enable))) return nullptr;
11959747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes            return khr_surface_commands[i].proc;
11960747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        }
11961747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
11962747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11963747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return nullptr;
1196409a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu}
1196509a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu
1196643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic PFN_vkVoidFunction intercept_extension_instance_commands(const char *name, VkInstance instance) {
1196743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    static const struct {
1196843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        const char *name;
1196943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        PFN_vkVoidFunction proc;
1197043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        bool instance_layer_data::*enable;
1197143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    } instance_extension_commands[] = {
1197243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        {"vkGetPhysicalDeviceQueueFamilyProperties2KHR",
1197343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis         reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceQueueFamilyProperties2KHR)},
11974582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        {"vkEnumeratePhysicalDeviceGroupsKHX",
11975582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen         reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDeviceGroupsKHX)},
1197643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    };
1197743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1197843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    for (size_t i = 0; i < ARRAY_SIZE(instance_extension_commands); i++) {
1197943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        if (!strcmp(instance_extension_commands[i].name, name)) {
1198043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            return instance_extension_commands[i].proc;
1198143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        }
1198243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    }
1198343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    return nullptr;
1198443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
11985b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11986cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski}  // namespace core_validation
11987d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11988d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu// vk_layer_logging.h expects these to be defined
11989d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11990bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugReportCallbackEXT(VkInstance instance,
11991bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                              const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
11992bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                              const VkAllocationCallbacks *pAllocator,
11993bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                              VkDebugReportCallbackEXT *pMsgCallback) {
1199489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu    return core_validation::CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
11995d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
11996d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11997bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT msgCallback,
11998bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                           const VkAllocationCallbacks *pAllocator) {
1199989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu    core_validation::DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);
12000d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
12001d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
12002bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL vkDebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags,
12003bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   VkDebugReportObjectTypeEXT objType, uint64_t object, size_t location,
12004bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
1200589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu    core_validation::DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, pMsg);
12006d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
12007d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
12008a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu// loader-layer interface v0, just wrappers since there is only a layer
12009d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
12010bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
12011bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                      VkExtensionProperties *pProperties) {
12012a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return core_validation::EnumerateInstanceExtensionProperties(pLayerName, pCount, pProperties);
1201308939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu}
1201408939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu
12015bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties(uint32_t *pCount,
12016bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                  VkLayerProperties *pProperties) {
12017a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return core_validation::EnumerateInstanceLayerProperties(pCount, pProperties);
1201808939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu}
1201908939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu
12020bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
12021bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                VkLayerProperties *pProperties) {
12022a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    // the layer command handles VK_NULL_HANDLE just fine internally
12023a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    assert(physicalDevice == VK_NULL_HANDLE);
12024a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return core_validation::EnumerateDeviceLayerProperties(VK_NULL_HANDLE, pCount, pProperties);
12025d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
12026d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
12027d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I WuVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
12028d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu                                                                                    const char *pLayerName, uint32_t *pCount,
12029d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu                                                                                    VkExtensionProperties *pProperties) {
12030a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    // the layer command handles VK_NULL_HANDLE just fine internally
12031a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    assert(physicalDevice == VK_NULL_HANDLE);
12032a8f4a23b1e9c068717eda47cc583a93f447c77e3Chia-I Wu    return core_validation::EnumerateDeviceExtensionProperties(VK_NULL_HANDLE, pLayerName, pCount, pProperties);
12033d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
12034d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
12035d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I WuVK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev, const char *funcName) {
1203689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu    return core_validation::GetDeviceProcAddr(dev, funcName);
12037d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
12038d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
12039d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I WuVK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) {
1204089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu    return core_validation::GetInstanceProcAddr(instance, funcName);
1204108939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu}
12042b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
12043bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_layerGetPhysicalDeviceProcAddr(VkInstance instance,
12044bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                           const char *funcName) {
12045b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    return core_validation::GetPhysicalDeviceProcAddr(instance, funcName);
12046b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young}
12047b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
12048b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark YoungVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct) {
12049b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    assert(pVersionStruct != NULL);
12050b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    assert(pVersionStruct->sType == LAYER_NEGOTIATE_INTERFACE_STRUCT);
12051b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
12052b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    // Fill in the function pointers if our version is at least capable of having the structure contain them.
12053b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    if (pVersionStruct->loaderLayerInterfaceVersion >= 2) {
12054b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        pVersionStruct->pfnGetInstanceProcAddr = vkGetInstanceProcAddr;
12055b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        pVersionStruct->pfnGetDeviceProcAddr = vkGetDeviceProcAddr;
12056b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        pVersionStruct->pfnGetPhysicalDeviceProcAddr = vk_layerGetPhysicalDeviceProcAddr;
12057b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    }
12058b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
12059b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    if (pVersionStruct->loaderLayerInterfaceVersion < CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
12060b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        core_validation::loader_layer_if_version = pVersionStruct->loaderLayerInterfaceVersion;
12061b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    } else if (pVersionStruct->loaderLayerInterfaceVersion > CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
12062b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        pVersionStruct->loaderLayerInterfaceVersion = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
12063b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    }
12064b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
12065b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    return VK_SUCCESS;
12066b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young}
12067