core_validation.cpp revision dab32891b91206a5bef7a3929b781e44fc1b7268
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>
45c8bee427d7a8ed0ccec899fbf47134d582dcafbdGabríel Arthúr Pétursson#include <memory>
46b9e992386a44404152747d66817a733aa127e281Jeremy Hayes#include <mutex>
4794c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis#include <set>
4868d157d34807071526e5d78b3b3b68c5a4c6185fMark Lobodzinski#include <sstream>
495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include <stdio.h>
505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include <stdlib.h>
515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include <string.h>
5294c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis#include <string>
53dd725b03ae4d1296a722d0ec5c9fe63941cabe4bChris Forbes#include <tuple>
545770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus#include <inttypes.h>
555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include "vk_loader_platform.h"
575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include "vk_dispatch_table_helper.h"
5868d157d34807071526e5d78b3b3b68c5a4c6185fMark Lobodzinski#include "vk_enum_string_helper.h"
595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#if defined(__GNUC__)
605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#pragma GCC diagnostic ignored "-Wwrite-strings"
615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#endif
625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#if defined(__GNUC__)
635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#pragma GCC diagnostic warning "-Wwrite-strings"
645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#endif
655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include "core_validation.h"
66c06c9b88f5f5bcc7033ba41d5547b048fa6015a4Mark Lobodzinski#include "buffer_validation.h"
675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include "vk_layer_table.h"
685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include "vk_layer_data.h"
695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include "vk_layer_extension_utils.h"
705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include "vk_layer_utils.h"
71b1f65702539fd041337fccd493dc6d38dd2a603eChris Forbes#include "spirv-tools/libspirv.h"
725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#if defined __ANDROID__
745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#include <android/log.h>
755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#define LOGCONSOLE(...) ((void)__android_log_print(ANDROID_LOG_INFO, "DS", __VA_ARGS__))
765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#else
77cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#define LOGCONSOLE(...)      \
78cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    {                        \
79cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        printf(__VA_ARGS__); \
80cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        printf("\n");        \
81c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    }
825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#endif
835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
845770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus// TODO: remove on NDK update (r15 will probably have proper STL impl)
855770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus#ifdef __ANDROID__
865770f8ad21c40b2475201e73e9368a899b6886d0Petr Krausnamespace std {
875770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
885770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraustemplate <typename T>
895770f8ad21c40b2475201e73e9368a899b6886d0Petr Krausstd::string to_string(T var) {
905770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    std::ostringstream ss;
915770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    ss << var;
925770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    return ss.str();
935770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus}
945770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus}
955770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus#endif
965770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
97d147a5463f8581604ca542aa1a44a27e512e0f60Mike Stroyan// This intentionally includes a cpp file
98d147a5463f8581604ca542aa1a44a27e512e0f60Mike Stroyan#include "vk_safe_struct.cpp"
99d147a5463f8581604ca542aa1a44a27e512e0f60Mike Stroyan
100d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wunamespace core_validation {
101d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
1025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisusing std::unordered_map;
1035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisusing std::unordered_set;
1040c55adf45a81f44300db04ec71a797d790ef103cTobin Ehlisusing std::unique_ptr;
1050c55adf45a81f44300db04ec71a797d790ef103cTobin Ehlisusing std::vector;
1060c55adf45a81f44300db04ec71a797d790ef103cTobin Ehlisusing std::string;
1070c55adf45a81f44300db04ec71a797d790ef103cTobin Ehlisusing std::stringstream;
1080c55adf45a81f44300db04ec71a797d790ef103cTobin Ehlisusing std::max;
1095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// WSI Image Objects bypass usual Image Object creation methods.  A special Memory
1115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Object value will be used to identify them internally.
1125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic const VkDeviceMemory MEMTRACKER_SWAP_CHAIN_IMAGE_KEY = (VkDeviceMemory)(-1);
113888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis// 2nd special memory handle used to flag object as unbound from memory
114888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlisstatic const VkDeviceMemory MEMORY_UNBOUND = VkDeviceMemory(~((uint64_t)(0)) - 1);
115b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis
1162e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill// A special value of (0xFFFFFFFF, 0xFFFFFFFF) indicates that the surface size will be determined
1172e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill// by the extent of a swapchain targeting the surface.
1182e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madillstatic const uint32_t kSurfaceSizeFromSwapchain = 0xFFFFFFFFu;
1192e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill
1205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// fwd decls
1215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstruct shader_module;
1225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
123f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbesstruct instance_layer_data {
124d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    VkInstance instance = VK_NULL_HANDLE;
125d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    debug_report_data *report_data = nullptr;
1265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<VkDebugReportCallbackEXT> logging_callback;
1279172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    VkLayerInstanceDispatchTable dispatch_table;
1289172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes
129219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes    CALL_STATE vkEnumeratePhysicalDevicesState = UNCALLED;
130219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes    uint32_t physical_devices_count = 0;
131b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    CALL_STATE vkEnumeratePhysicalDeviceGroupsState = UNCALLED;
132b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    uint32_t physical_device_groups_count = 0;
133219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes    CHECK_DISABLED disabled = {};
134219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes
135f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes    unordered_map<VkPhysicalDevice, PHYSICAL_DEVICE_STATE> physical_device_map;
136747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    unordered_map<VkSurfaceKHR, SURFACE_STATE> surface_map;
137747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
1380cf009a4e2a5c22e4645f343c7a998f188a22015Chris Forbes    InstanceExtensions extensions;
139f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes};
140f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes
141f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbesstruct layer_data {
142f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes    debug_report_data *report_data = nullptr;
1434a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkLayerDispatchTable dispatch_table;
14494c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis
145a149f1a0cb39b48b19822c8cf9ef2426cd2251dfMark Lobodzinski    DeviceExtensions extensions = {};
146cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    unordered_set<VkQueue> queues;  // All queues under given device
1475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Layer specific data
148d31a44af6da568692a73201825459689c9431867Tobin Ehlis    unordered_map<VkSampler, unique_ptr<SAMPLER_STATE>> samplerMap;
14979fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis    unordered_map<VkImageView, unique_ptr<IMAGE_VIEW_STATE>> imageViewMap;
1501facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    unordered_map<VkImage, unique_ptr<IMAGE_STATE>> imageMap;
15139267c0c27b8f032f05a6747eb02d4508247fdc1Tobin Ehlis    unordered_map<VkBufferView, unique_ptr<BUFFER_VIEW_STATE>> bufferViewMap;
1525cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    unordered_map<VkBuffer, unique_ptr<BUFFER_STATE>> bufferMap;
1534c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    unordered_map<VkPipeline, PIPELINE_STATE *> pipelineMap;
1548d6a38de0389036581ada119e548180c614fe0efChris Forbes    unordered_map<VkCommandPool, COMMAND_POOL_NODE> commandPoolMap;
155a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis    unordered_map<VkDescriptorPool, DESCRIPTOR_POOL_STATE *> descriptorPoolMap;
156397d27da37095073c8b86f9ff5289d0a39ce486eTobin Ehlis    unordered_map<VkDescriptorSet, cvdescriptorset::DescriptorSet *> setMap;
157c8bee427d7a8ed0ccec899fbf47134d582dcafbdGabríel Arthúr Pétursson    unordered_map<VkDescriptorSetLayout, std::unique_ptr<cvdescriptorset::DescriptorSetLayout>> descriptorSetLayoutMap;
1585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkPipelineLayout, PIPELINE_LAYOUT_NODE> pipelineLayoutMap;
15957fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    unordered_map<VkDeviceMemory, unique_ptr<DEVICE_MEM_INFO>> memObjMap;
1605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkFence, FENCE_NODE> fenceMap;
16136c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlis    unordered_map<VkQueue, QUEUE_STATE> queueMap;
1624710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis    unordered_map<VkEvent, EVENT_STATE> eventMap;
1635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<QueryObject, bool> queryToStateMap;
1645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkQueryPool, QUERY_POOL_NODE> queryPoolMap;
1655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkSemaphore, SEMAPHORE_NODE> semaphoreMap;
16672d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis    unordered_map<VkCommandBuffer, GLOBAL_CB_NODE *> commandBufferMap;
167c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    unordered_map<VkFramebuffer, unique_ptr<FRAMEBUFFER_STATE>> frameBufferMap;
1685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<VkImage, vector<ImageSubresourcePair>> imageSubresourceMap;
1695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> imageLayoutMap;
170127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis    unordered_map<VkRenderPass, unique_ptr<RENDER_PASS_STATE>> renderPassMap;
171918c283ac4f8c604b79abd0c8b5706d2a7352a34Chris Forbes    unordered_map<VkShaderModule, unique_ptr<shader_module>> shaderModuleMap;
1726246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    unordered_map<VkDescriptorUpdateTemplateKHR, unique_ptr<TEMPLATE_STATE>> desc_template_map;
17316a1f8f9c4af479b1873e82ff02360817fb658acChris Forbes    unordered_map<VkSwapchainKHR, std::unique_ptr<SWAPCHAIN_NODE>> swapchainMap;
17407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
175d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    VkDevice device = VK_NULL_HANDLE;
176ec85232c4d8d9ddf7d2ae57cb8203c5ab52c1106Mark Lobodzinski    VkPhysicalDevice physical_device = VK_NULL_HANDLE;
1775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
178cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    instance_layer_data *instance_data = nullptr;  // from device to enclosing instance
17907a464bd7fec9583f346b8c4b8d43c88d2e9ffa4Chris Forbes
180f71dd305f197826a61f398bff725267a20ea1d90Chris Forbes    VkPhysicalDeviceFeatures enabled_features = {};
1815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Device specific data
182d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    PHYS_DEV_PROPERTIES_NODE phys_dev_properties = {};
183d3578035fec44db2380099c2f59d3e4d8e0b98d6Chris Forbes    VkPhysicalDeviceMemoryProperties phys_dev_mem_props = {};
184e47dbc3f3340fa177d877a67b2adb76a570027e5Mark Lobodzinski    VkPhysicalDeviceProperties phys_dev_props = {};
1855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis};
1865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
187b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis// TODO : Do we need to guard access to layer_data_map w/ lock?
188b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlisstatic unordered_map<void *, layer_data *> layer_data_map;
189f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbesstatic unordered_map<void *, instance_layer_data *> instance_layer_data_map;
190b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis
191b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Youngstatic uint32_t loader_layer_if_version = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
192b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
193e11120777bcd1543455d1de54b89292879bcd2bbChia-I Wustatic const VkLayerProperties global_layer = {
194f1ea418f193d10a8455cdf47e0eeeeb1f4d8b5bfJon Ashburn    "VK_LAYER_LUNARG_core_validation", VK_LAYER_API_VERSION, 1, "LunarG Validation Layer",
195e11120777bcd1543455d1de54b89292879bcd2bbChia-I Wu};
1965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
197cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskitemplate <class TCreateInfo>
198cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskivoid ValidateLayerOrdering(const TCreateInfo &createInfo) {
1995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool foundLayer = false;
2005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < createInfo.enabledLayerCount; ++i) {
201e11120777bcd1543455d1de54b89292879bcd2bbChia-I Wu        if (!strcmp(createInfo.ppEnabledLayerNames[i], global_layer.layerName)) {
2025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            foundLayer = true;
2035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
2045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // This has to be logged to console as we don't have a callback at this point.
2055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!foundLayer && !strcmp(createInfo.ppEnabledLayerNames[0], "VK_LAYER_GOOGLE_unique_objects")) {
206bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            LOGCONSOLE("Cannot activate layer VK_LAYER_GOOGLE_unique_objects prior to activating %s.", global_layer.layerName);
2075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
2085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
2105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Code imported from shader_checker
2125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic void build_def_index(shader_module *);
2135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// A forward iterator over spirv instructions. Provides easy access to len, opcode, and content words
2155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// without the caller needing to care too much about the physical SPIRV module layout.
2165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstruct spirv_inst_iter {
2175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<uint32_t>::const_iterator zero;
2185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<uint32_t>::const_iterator it;
2195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
220b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes    uint32_t len() {
221b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes        auto result = *it >> 16;
222b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes        assert(result > 0);
223b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes        return result;
224b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes    }
225b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes
2265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t opcode() { return *it & 0x0ffffu; }
227b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes
228b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes    uint32_t const &word(unsigned n) {
229b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes        assert(n < len());
230b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes        return it[n];
231b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes    }
232b95616f79b105741b1399b01d527a8ef3b7ccfb7Chris Forbes
2335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t offset() { return (uint32_t)(it - zero); }
2345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter() {}
2365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter(std::vector<uint32_t>::const_iterator zero, std::vector<uint32_t>::const_iterator it) : zero(zero), it(it) {}
2385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool operator==(spirv_inst_iter const &other) { return it == other.it; }
2405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    bool operator!=(spirv_inst_iter const &other) { return it != other.it; }
2425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
243cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    spirv_inst_iter operator++(int) {  // x++
2445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        spirv_inst_iter ii = *this;
2455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        it += len();
2465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return ii;
2475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
249cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    spirv_inst_iter operator++() {  // ++x;
2505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        it += len();
2515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return *this;
2525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
25425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // The iterator and the value are the same thing.
2555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter &operator*() { return *this; }
2565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter const &operator*() const { return *this; }
2575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis};
2585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstruct shader_module {
26025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // The spirv image itself
2615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    vector<uint32_t> words;
26225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // A mapping of <id> to the first word of its def. this is useful because walking type
26325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // trees, constant expressions, etc requires jumping all over the instruction stream.
2645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_map<unsigned, unsigned> def_index;
265c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski    bool has_valid_spirv;
2665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    shader_module(VkShaderModuleCreateInfo const *pCreateInfo)
2685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        : words((uint32_t *)pCreateInfo->pCode, (uint32_t *)pCreateInfo->pCode + pCreateInfo->codeSize / sizeof(uint32_t)),
269c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski          def_index(),
270c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski          has_valid_spirv(true) {
2715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        build_def_index(this);
2725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
274c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski    shader_module() : has_valid_spirv(false) {}
275c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski
27625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Expose begin() / end() to enable range-based for
277cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    spirv_inst_iter begin() const { return spirv_inst_iter(words.begin(), words.begin() + 5); }  // First insn
278cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    spirv_inst_iter end() const { return spirv_inst_iter(words.begin(), words.end()); }          // Just past last insn
27925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Given an offset into the module, produce an iterator there.
2805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter at(unsigned offset) const { return spirv_inst_iter(words.begin(), words.begin() + offset); }
2815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
28225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Gets an iterator to the definition of an id
2835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter get_def(unsigned id) const {
2845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto it = def_index.find(id);
2855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (it == def_index.end()) {
2865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return end();
2875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
2885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return at(it->second);
2895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis};
2915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// TODO : This can be much smarter, using separate locks for separate global data
293b9e992386a44404152747d66817a733aa127e281Jeremy Hayesstatic std::mutex global_lock;
294593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
29579fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis// Return IMAGE_VIEW_STATE ptr for specified imageView or else NULL
2969a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisIMAGE_VIEW_STATE *GetImageViewState(const layer_data *dev_data, VkImageView image_view) {
2972c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    auto iv_it = dev_data->imageViewMap.find(image_view);
2982c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    if (iv_it == dev_data->imageViewMap.end()) {
2992c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis        return nullptr;
3002c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    }
3012c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    return iv_it->second.get();
3022c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis}
3039a55ca3674bb3fac3fbdfca9515a16a224aa9055Tobin Ehlis// Return sampler node ptr for specified sampler or else NULL
3049a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisSAMPLER_STATE *GetSamplerState(const layer_data *dev_data, VkSampler sampler) {
3052c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    auto sampler_it = dev_data->samplerMap.find(sampler);
3062c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    if (sampler_it == dev_data->samplerMap.end()) {
3079a55ca3674bb3fac3fbdfca9515a16a224aa9055Tobin Ehlis        return nullptr;
3089a55ca3674bb3fac3fbdfca9515a16a224aa9055Tobin Ehlis    }
3099a55ca3674bb3fac3fbdfca9515a16a224aa9055Tobin Ehlis    return sampler_it->second.get();
3109a55ca3674bb3fac3fbdfca9515a16a224aa9055Tobin Ehlis}
3115cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis// Return image state ptr for specified image or else NULL
3129a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisIMAGE_STATE *GetImageState(const layer_data *dev_data, VkImage image) {
3136d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis    auto img_it = dev_data->imageMap.find(image);
3146d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis    if (img_it == dev_data->imageMap.end()) {
3156d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis        return nullptr;
3166d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis    }
3176d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis    return img_it->second.get();
3186d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis}
3195cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis// Return buffer state ptr for specified buffer or else NULL
3209a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisBUFFER_STATE *GetBufferState(const layer_data *dev_data, VkBuffer buffer) {
3212c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    auto buff_it = dev_data->bufferMap.find(buffer);
3222c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    if (buff_it == dev_data->bufferMap.end()) {
3238718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis        return nullptr;
3248718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis    }
3258718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis    return buff_it->second.get();
3268718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis}
327b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis// Return swapchain node for specified swapchain or else NULL
3289a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisSWAPCHAIN_NODE *GetSwapchainNode(const layer_data *dev_data, VkSwapchainKHR swapchain) {
32916a1f8f9c4af479b1873e82ff02360817fb658acChris Forbes    auto swp_it = dev_data->swapchainMap.find(swapchain);
33016a1f8f9c4af479b1873e82ff02360817fb658acChris Forbes    if (swp_it == dev_data->swapchainMap.end()) {
331b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis        return nullptr;
332b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis    }
3333f687bf405355f3eec6bd1bc0e8d04daba37a0f9Tobin Ehlis    return swp_it->second.get();
334b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis}
3352f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis// Return buffer node ptr for specified buffer or else NULL
3369a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisBUFFER_VIEW_STATE *GetBufferViewState(const layer_data *dev_data, VkBufferView buffer_view) {
33751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto bv_it = dev_data->bufferViewMap.find(buffer_view);
33851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (bv_it == dev_data->bufferViewMap.end()) {
3392f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis        return nullptr;
3402f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis    }
3412f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis    return bv_it->second.get();
3422f2db584f5d79892bd84d0a24b8ca3499985a5c2Tobin Ehlis}
3438718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis
3449a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisFENCE_NODE *GetFenceNode(layer_data *dev_data, VkFence fence) {
34566fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    auto it = dev_data->fenceMap.find(fence);
34666fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    if (it == dev_data->fenceMap.end()) {
34766fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes        return nullptr;
34866fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    }
34966fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    return &it->second;
35066fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes}
35166fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes
3529a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisEVENT_STATE *GetEventNode(layer_data *dev_data, VkEvent event) {
3539556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis    auto it = dev_data->eventMap.find(event);
3549556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis    if (it == dev_data->eventMap.end()) {
3559556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis        return nullptr;
3569556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis    }
3579556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis    return &it->second;
3589556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis}
3599556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis
3609a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisQUERY_POOL_NODE *GetQueryPoolNode(layer_data *dev_data, VkQueryPool query_pool) {
361ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    auto it = dev_data->queryPoolMap.find(query_pool);
362ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    if (it == dev_data->queryPoolMap.end()) {
363ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis        return nullptr;
364ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    }
365ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    return &it->second;
366ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis}
367ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis
3689a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisQUEUE_STATE *GetQueueState(layer_data *dev_data, VkQueue queue) {
36966fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    auto it = dev_data->queueMap.find(queue);
37066fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    if (it == dev_data->queueMap.end()) {
37166fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes        return nullptr;
37266fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    }
37366fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes    return &it->second;
37466fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes}
37566fb98d19a758f79dd11ba354e47d0c66c6aac1eChris Forbes
3769a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisSEMAPHORE_NODE *GetSemaphoreNode(layer_data *dev_data, VkSemaphore semaphore) {
3775e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes    auto it = dev_data->semaphoreMap.find(semaphore);
3785e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes    if (it == dev_data->semaphoreMap.end()) {
3795e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes        return nullptr;
3805e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes    }
3815e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes    return &it->second;
3825e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes}
3835e92f3cfdca6a52a3dcefd053c41f728bd036cebChris Forbes
3849a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisCOMMAND_POOL_NODE *GetCommandPoolNode(layer_data *dev_data, VkCommandPool pool) {
3858d6a38de0389036581ada119e548180c614fe0efChris Forbes    auto it = dev_data->commandPoolMap.find(pool);
3868d6a38de0389036581ada119e548180c614fe0efChris Forbes    if (it == dev_data->commandPoolMap.end()) {
3878d6a38de0389036581ada119e548180c614fe0efChris Forbes        return nullptr;
3888d6a38de0389036581ada119e548180c614fe0efChris Forbes    }
3898d6a38de0389036581ada119e548180c614fe0efChris Forbes    return &it->second;
3908d6a38de0389036581ada119e548180c614fe0efChris Forbes}
3913bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes
3929a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisPHYSICAL_DEVICE_STATE *GetPhysicalDeviceState(instance_layer_data *instance_data, VkPhysicalDevice phys) {
393f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes    auto it = instance_data->physical_device_map.find(phys);
394f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbes    if (it == instance_data->physical_device_map.end()) {
3953bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes        return nullptr;
3963bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes    }
3973bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes    return &it->second;
3983bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes}
3993bb2c67470811e4eaf908b3eade82f73aa3f87bcChris Forbes
4009a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisSURFACE_STATE *GetSurfaceState(instance_layer_data *instance_data, VkSurfaceKHR surface) {
401747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    auto it = instance_data->surface_map.find(surface);
402747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    if (it == instance_data->surface_map.end()) {
403747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        return nullptr;
404747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
405747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return &it->second;
406747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
407747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
408f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis// Return ptr to memory binding for given handle of specified type
4097a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinskistatic BINDABLE *GetObjectMemBinding(layer_data *dev_data, uint64_t handle, VulkanObjectType type) {
4105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (type) {
4117a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        case kVulkanObjectTypeImage:
4129a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            return GetImageState(dev_data, VkImage(handle));
4137a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        case kVulkanObjectTypeBuffer:
4149a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            return GetBufferState(dev_data, VkBuffer(handle));
415cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
416cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
4175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
41894c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis    return nullptr;
4195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
42072d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis// prototype
4219a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisGLOBAL_CB_NODE *GetCBNode(layer_data const *, const VkCommandBuffer);
42272d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis
4235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Return ptr to info in map container containing mem, or NULL if not found
4245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Calls to this function should be wrapped in mutex
4259a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisDEVICE_MEM_INFO *GetMemObjInfo(const layer_data *dev_data, const VkDeviceMemory mem) {
42657fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    auto mem_it = dev_data->memObjMap.find(mem);
42757fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    if (mem_it == dev_data->memObjMap.end()) {
4285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return NULL;
4295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
43057fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    return mem_it->second.get();
4315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
4325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
43351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void add_mem_obj_info(layer_data *dev_data, void *object, const VkDeviceMemory mem,
4345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                             const VkMemoryAllocateInfo *pAllocateInfo) {
4355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(object != NULL);
4365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
43751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    dev_data->memObjMap[mem] = unique_ptr<DEVICE_MEM_INFO>(new DEVICE_MEM_INFO(object, mem, pAllocateInfo));
4385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
439dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis
440cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis// For given bound_object_handle, bound to given mem allocation, verify that the range for the bound object is valid
4417a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinskistatic bool ValidateMemoryIsValid(layer_data *dev_data, VkDeviceMemory mem, uint64_t bound_object_handle, VulkanObjectType type,
4427a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski                                  const char *functionName) {
4439a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
444f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    if (mem_info) {
445f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis        if (!mem_info->bound_ranges[bound_object_handle].valid) {
446f48a83f5b5548cd46a12770c7542ff902537ad3eKarl Schultz            return log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
4479b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                           HandleToUint64(mem), __LINE__, MEMTRACK_INVALID_MEM_REGION, "MEM",
448dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis                           "%s: Cannot read invalid region of memory allocation 0x%" PRIx64 " for bound %s object 0x%" PRIx64
449dc21d4c322604e04e0b8433970f6a1ced6a0b647Tobin Ehlis                           ", please fill the memory before using.",
4509b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                           functionName, HandleToUint64(mem), object_string[type], bound_object_handle);
451f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis        }
452f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    }
453f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    return false;
454f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis}
4551facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis// For given image_state
4561facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis//  If mem is special swapchain key, then verify that image_state valid member is true
457f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis//  Else verify that the image's bound memory range is valid
45860568995aca225f81acda8ce40cfabbea2c19397Mark Lobodzinskibool ValidateImageMemoryIsValid(layer_data *dev_data, IMAGE_STATE *image_state, const char *functionName) {
459e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis    if (image_state->binding.mem == MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
4601facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        if (!image_state->valid) {
461f48a83f5b5548cd46a12770c7542ff902537ad3eKarl Schultz            return log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
4629b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                           HandleToUint64(image_state->binding.mem), __LINE__, MEMTRACK_INVALID_MEM_REGION, "MEM",
463414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                           "%s: Cannot read invalid swapchain image 0x%" PRIx64 ", please fill the memory before using.",
4649b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                           functionName, HandleToUint64(image_state->image));
4655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
4665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
4679b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus        return ValidateMemoryIsValid(dev_data, image_state->binding.mem, HandleToUint64(image_state->image), kVulkanObjectTypeImage,
4689b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                     functionName);
4695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
4705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return false;
4715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
4725cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis// For given buffer_state, verify that the range it's bound to is valid
473c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinskibool ValidateBufferMemoryIsValid(layer_data *dev_data, BUFFER_STATE *buffer_state, const char *functionName) {
4749b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    return ValidateMemoryIsValid(dev_data, buffer_state->binding.mem, HandleToUint64(buffer_state->buffer), kVulkanObjectTypeBuffer,
4759b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                 functionName);
476f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis}
477f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis// For the given memory allocation, set the range bound by the given handle object to the valid param value
478f989de4217bce0f293121d0da53dc8328276370fTobin Ehlisstatic void SetMemoryValid(layer_data *dev_data, VkDeviceMemory mem, uint64_t handle, bool valid) {
4799a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
480f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    if (mem_info) {
481f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis        mem_info->bound_ranges[handle].valid = valid;
482f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis    }
483f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis}
484f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis// For given image node
4851facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis//  If mem is special swapchain key, then set entire image_state to valid param value
486f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis//  Else set the image's bound memory range to valid param value
487623784ad78c8b77a78c4db613db974c12e5f5a43Mark Lobodzinskivoid SetImageMemoryValid(layer_data *dev_data, IMAGE_STATE *image_state, bool valid) {
488e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis    if (image_state->binding.mem == MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
4891facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        image_state->valid = valid;
4905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
4919b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus        SetMemoryValid(dev_data, image_state->binding.mem, HandleToUint64(image_state->image), valid);
4925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
4935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
494f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis// For given buffer node set the buffer's bound memory range to valid param value
495c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinskivoid SetBufferMemoryValid(layer_data *dev_data, BUFFER_STATE *buffer_state, bool valid) {
4969b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    SetMemoryValid(dev_data, buffer_state->binding.mem, HandleToUint64(buffer_state->buffer), valid);
497f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis}
498ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
49956f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis// Create binding link between given sampler and command buffer node
500d31a44af6da568692a73201825459689c9431867Tobin Ehlisvoid AddCommandBufferBindingSampler(GLOBAL_CB_NODE *cb_node, SAMPLER_STATE *sampler_state) {
501d31a44af6da568692a73201825459689c9431867Tobin Ehlis    sampler_state->cb_bindings.insert(cb_node);
5029b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    cb_node->object_bindings.insert({HandleToUint64(sampler_state->sampler), kVulkanObjectTypeSampler});
50356f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis}
50456f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis
50556f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis// Create binding link between given image node and command buffer node
5061facd2c91911508b9fb61f54a56269841299f663Tobin Ehlisvoid AddCommandBufferBindingImage(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, IMAGE_STATE *image_state) {
507ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    // Skip validation if this image was created through WSI
508e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis    if (image_state->binding.mem != MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
509ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // First update CB binding in MemObj mini CB list
510d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis        for (auto mem_binding : image_state->GetBoundMemory()) {
5119a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            DEVICE_MEM_INFO *pMemInfo = GetMemObjInfo(dev_data, mem_binding);
512d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            if (pMemInfo) {
513d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis                pMemInfo->cb_bindings.insert(cb_node);
514d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis                // Now update CBInfo's Mem reference list
515d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis                cb_node->memObjs.insert(mem_binding);
516d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            }
517ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        }
518f940225c9e5e3e14b3f5a32d3ea360b585614600Tobin Ehlis        // Now update cb binding for image
5199b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus        cb_node->object_bindings.insert({HandleToUint64(image_state->image), kVulkanObjectTypeImage});
5201facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        image_state->cb_bindings.insert(cb_node);
521ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    }
522ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis}
523ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
52403ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis// Create binding link between given image view node and its image with command buffer node
52503ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlisvoid AddCommandBufferBindingImageView(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, IMAGE_VIEW_STATE *view_state) {
52603ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis    // First add bindings for imageView
52703ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis    view_state->cb_bindings.insert(cb_node);
5289b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    cb_node->object_bindings.insert({HandleToUint64(view_state->image_view), kVulkanObjectTypeImageView});
5299a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto image_state = GetImageState(dev_data, view_state->create_info.image);
53003ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis    // Add bindings for image within imageView
5311facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (image_state) {
5321facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        AddCommandBufferBindingImage(dev_data, cb_node, image_state);
53303ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis    }
53403ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis}
53503ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis
536ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis// Create binding link between given buffer node and command buffer node
5375cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlisvoid AddCommandBufferBindingBuffer(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, BUFFER_STATE *buffer_state) {
538ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    // First update CB binding in MemObj mini CB list
5395cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    for (auto mem_binding : buffer_state->GetBoundMemory()) {
5409a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        DEVICE_MEM_INFO *pMemInfo = GetMemObjInfo(dev_data, mem_binding);
541d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis        if (pMemInfo) {
542d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            pMemInfo->cb_bindings.insert(cb_node);
543d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            // Now update CBInfo's Mem reference list
544d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis            cb_node->memObjs.insert(mem_binding);
545d87d172d120ea3f00bfd34335537332d7ce61a89Tobin Ehlis        }
546ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    }
547ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    // Now update cb binding for buffer
5489b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    cb_node->object_bindings.insert({HandleToUint64(buffer_state->buffer), kVulkanObjectTypeBuffer});
5495cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    buffer_state->cb_bindings.insert(cb_node);
550ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis}
551ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
55277b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis// Create binding link between given buffer view node and its buffer with command buffer node
55377b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlisvoid AddCommandBufferBindingBufferView(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, BUFFER_VIEW_STATE *view_state) {
55477b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis    // First add bindings for bufferView
55577b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis    view_state->cb_bindings.insert(cb_node);
5569b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    cb_node->object_bindings.insert({HandleToUint64(view_state->buffer_view), kVulkanObjectTypeBufferView});
5579a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto buffer_state = GetBufferState(dev_data, view_state->create_info.buffer);
55877b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis    // Add bindings for buffer within bufferView
5595cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (buffer_state) {
5605cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        AddCommandBufferBindingBuffer(dev_data, cb_node, buffer_state);
56177b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis    }
56277b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis}
56377b6217754b9c167b08cb151e70b41a948e36277Tobin Ehlis
564400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis// For every mem obj bound to particular CB, free bindings related to that CB
565d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlisstatic void clear_cmd_buf_and_mem_references(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
566d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis    if (cb_node) {
567d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis        if (cb_node->memObjs.size() > 0) {
568d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis            for (auto mem : cb_node->memObjs) {
5699a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                DEVICE_MEM_INFO *pInfo = GetMemObjInfo(dev_data, mem);
5705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (pInfo) {
571d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                    pInfo->cb_bindings.erase(cb_node);
5725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
5735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
574d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis            cb_node->memObjs.clear();
5755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
576d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis        cb_node->validate_functions.clear();
5775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
5795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
580f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis// Clear a single object binding from given memory object, or report error if binding is missing
5817a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinskistatic bool ClearMemoryObjectBinding(layer_data *dev_data, uint64_t handle, VulkanObjectType type, VkDeviceMemory mem) {
5829a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
583f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    // This obj is bound to a memory object. Remove the reference to this object in that memory object's list
584d4cd34fd49caa759cf01cafa5fa271401b17c3b9Jeremy Hayes    if (mem_info) {
585d4cd34fd49caa759cf01cafa5fa271401b17c3b9Jeremy Hayes        mem_info->obj_bindings.erase({handle, type});
586f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    }
587f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    return false;
588f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis}
589f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis
590f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis// ClearMemoryObjectBindings clears the binding of objects to memory
591f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis//  For the given object it pulls the memory bindings and makes sure that the bindings
592f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis//  no longer refer to the object being cleared. This occurs when objects are destroyed.
5937a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinskibool ClearMemoryObjectBindings(layer_data *dev_data, uint64_t handle, VulkanObjectType type) {
594f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    bool skip = false;
595f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    BINDABLE *mem_binding = GetObjectMemBinding(dev_data, handle, type);
596f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    if (mem_binding) {
597f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        if (!mem_binding->sparse) {
598f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis            skip = ClearMemoryObjectBinding(dev_data, handle, type, mem_binding->binding.mem);
599cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        } else {  // Sparse, clear all bindings
600bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            for (auto &sparse_mem_binding : mem_binding->sparse_bindings) {
601f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                skip |= ClearMemoryObjectBinding(dev_data, handle, type, sparse_mem_binding.mem);
6025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
6035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
605f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    return skip;
6065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
6075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
608888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis// For given mem object, verify that it is not null or UNBOUND, if it is, report error. Return skip value.
609888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlisbool VerifyBoundMemoryIsValid(const layer_data *dev_data, VkDeviceMemory mem, uint64_t handle, const char *api_name,
61035ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                              const char *type_name, UNIQUE_VALIDATION_ERROR_CODE error_code) {
611888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    bool result = false;
612888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    if (VK_NULL_HANDLE == mem) {
613888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis        result = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, handle,
614cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                         __LINE__, error_code, "MEM", "%s: Vk%s object 0x%" PRIxLEAST64
615cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                      " used with no memory bound. Memory should be bound by calling "
616cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                      "vkBind%sMemory(). %s",
61735ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                         api_name, type_name, handle, type_name, validation_error_map[error_code]);
618888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    } else if (MEMORY_UNBOUND == mem) {
619888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis        result = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, handle,
620cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                         __LINE__, error_code, "MEM", "%s: Vk%s object 0x%" PRIxLEAST64
621cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                      " used with no memory bound and previously bound memory was freed. "
622cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                      "Memory must not be freed prior to this operation. %s",
62335ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                         api_name, type_name, handle, validation_error_map[error_code]);
624888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    }
625888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis    return result;
626888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis}
627888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis
628b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski// Check to see if memory was ever bound to this image
62935ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlisbool ValidateMemoryIsBoundToImage(const layer_data *dev_data, const IMAGE_STATE *image_state, const char *api_name,
63035ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                                  UNIQUE_VALIDATION_ERROR_CODE error_code) {
631b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    bool result = false;
6321facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (0 == (static_cast<uint32_t>(image_state->createInfo.flags) & VK_IMAGE_CREATE_SPARSE_BINDING_BIT)) {
6339b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus        result = VerifyBoundMemoryIsValid(dev_data, image_state->binding.mem, HandleToUint64(image_state->image), api_name, "Image",
6349b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                          error_code);
635b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    }
636b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    return result;
637b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski}
638b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski
639b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski// Check to see if memory was bound to this buffer
64035ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlisbool ValidateMemoryIsBoundToBuffer(const layer_data *dev_data, const BUFFER_STATE *buffer_state, const char *api_name,
64135ec5e14e463d342b74ffe33ee542be13d5c6639Tobin Ehlis                                   UNIQUE_VALIDATION_ERROR_CODE error_code) {
642b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    bool result = false;
6435cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (0 == (static_cast<uint32_t>(buffer_state->createInfo.flags) & VK_BUFFER_CREATE_SPARSE_BINDING_BIT)) {
6449b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus        result = VerifyBoundMemoryIsValid(dev_data, buffer_state->binding.mem, HandleToUint64(buffer_state->buffer), api_name,
6459b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                          "Buffer", error_code);
646b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    }
647b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski    return result;
648b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski}
649b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski
6503a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// SetMemBinding is used to establish immutable, non-sparse binding between a single image/buffer object and memory object.
6513a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// Corresponding valid usage checks are in ValidateSetMemBinding().
6527a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinskistatic void SetMemBinding(layer_data *dev_data, VkDeviceMemory mem, uint64_t handle, VulkanObjectType type, const char *apiName) {
653c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton    if (mem != VK_NULL_HANDLE) {
654c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        BINDABLE *mem_binding = GetObjectMemBinding(dev_data, handle, type);
655c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        assert(mem_binding);
656c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
657c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        if (mem_info) {
658c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton            mem_info->obj_bindings.insert({handle, type});
659c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton            // For image objects, make sure default memory state is correctly set
660c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton            // TODO : What's the best/correct way to handle this?
6617a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski            if (kVulkanObjectTypeImage == type) {
662c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                auto const image_state = GetImageState(dev_data, VkImage(handle));
663c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                if (image_state) {
664c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                    VkImageCreateInfo ici = image_state->createInfo;
665c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                    if (ici.usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
666c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                        // TODO::  More memory state transition stuff.
667c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                    }
668c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                }
669c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton            }
670c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton            mem_binding->binding.mem = mem;
671c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        }
672c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton    }
673c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton}
6743a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton
6753a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// Valid usage checks for a call to SetMemBinding().
6763a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// For NULL mem case, output warning
6773a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// Make sure given object is in global object map
6783a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton//  IF a previous binding existed, output validation error
6793a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton//  Otherwise, add reference from objectInfo to memoryInfo
6803a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton//  Add reference off of objInfo
6813a6c2a8f5135475de5be6de7675ffd9dd27b30d3Cort Stratton// TODO: We may need to refactor or pass in multiple valid usage statements to handle multiple valid usage conditions.
6827a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinskistatic bool ValidateSetMemBinding(layer_data *dev_data, VkDeviceMemory mem, uint64_t handle, VulkanObjectType type,
683c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton                                  const char *apiName) {
6843251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
685f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    // It's an error to bind an object to NULL memory
686d3876b4ff7c293a14f73fe3622513d1fa91bf2d0Jeremy Hayes    if (mem != VK_NULL_HANDLE) {
687f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        BINDABLE *mem_binding = GetObjectMemBinding(dev_data, handle, type);
688888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis        assert(mem_binding);
68910ffe2d353eaff714ed92a2835af77d8b5042d31Cort        if (mem_binding->sparse) {
690315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            UNIQUE_VALIDATION_ERROR_CODE error_code = VALIDATION_ERROR_1740082a;
69110ffe2d353eaff714ed92a2835af77d8b5042d31Cort            const char *handle_type = "IMAGE";
69274300755ed9ec780d6073af71e47f201217008d6Cort Stratton            if (strcmp(apiName, "vkBindBufferMemory()") == 0) {
693315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                error_code = VALIDATION_ERROR_1700080c;
69410ffe2d353eaff714ed92a2835af77d8b5042d31Cort                handle_type = "BUFFER";
69510ffe2d353eaff714ed92a2835af77d8b5042d31Cort            } else {
69674300755ed9ec780d6073af71e47f201217008d6Cort Stratton                assert(strcmp(apiName, "vkBindImageMemory()") == 0);
69710ffe2d353eaff714ed92a2835af77d8b5042d31Cort            }
6983251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
6999b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(mem), __LINE__, error_code, "MEM",
7003251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "In %s, attempting to bind memory (0x%" PRIxLEAST64 ") to object (0x%" PRIxLEAST64
7013251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            ") which was created with sparse memory flags (VK_%s_CREATE_SPARSE_*_BIT). %s",
7029b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            apiName, HandleToUint64(mem), handle, handle_type, validation_error_map[error_code]);
70310ffe2d353eaff714ed92a2835af77d8b5042d31Cort        }
7049a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
705888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis        if (mem_info) {
7069a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            DEVICE_MEM_INFO *prev_binding = GetMemObjInfo(dev_data, mem_binding->binding.mem);
707888cae09036ec622d6014e18efbda55e6226cf22Tobin Ehlis            if (prev_binding) {
708315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                UNIQUE_VALIDATION_ERROR_CODE error_code = VALIDATION_ERROR_17400828;
70974300755ed9ec780d6073af71e47f201217008d6Cort Stratton                if (strcmp(apiName, "vkBindBufferMemory()") == 0) {
710315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                    error_code = VALIDATION_ERROR_1700080a;
71198c2a17e1a549df84f4239f619bc0955f632cb43Cort                } else {
71274300755ed9ec780d6073af71e47f201217008d6Cort Stratton                    assert(strcmp(apiName, "vkBindImageMemory()") == 0);
71398c2a17e1a549df84f4239f619bc0955f632cb43Cort                }
7143251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
7159b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(mem), __LINE__, error_code, "MEM",
7163251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "In %s, attempting to bind memory (0x%" PRIxLEAST64 ") to object (0x%" PRIxLEAST64
7173251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                ") which has already been bound to mem object 0x%" PRIxLEAST64 ". %s",
7189b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                apiName, HandleToUint64(mem), handle, HandleToUint64(prev_binding->mem),
7193251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                validation_error_map[error_code]);
720f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis            } else if (mem_binding->binding.mem == MEMORY_UNBOUND) {
7213251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
7229b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(mem), __LINE__, MEMTRACK_REBIND_OBJECT, "MEM",
7233251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "In %s, attempting to bind memory (0x%" PRIxLEAST64 ") to object (0x%" PRIxLEAST64
7243251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                ") which was previous bound to memory that has since been freed. Memory bindings are immutable in "
7253251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "Vulkan so this attempt to bind to new memory is not allowed.",
7269b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                apiName, HandleToUint64(mem), handle);
7275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
7285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7303251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
7315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
7325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// For NULL mem case, clear any previous binding Else...
7345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Make sure given object is in its object map
7355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  IF a previous binding existed, update binding
7365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Add reference from objectInfo to memoryInfo
7375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Add reference off of object's binding info
7380a1ce3dfd81c9f4efbe46f5ba5ddaea70bc4aa61Chris Forbes// Return VK_TRUE if addition is successful, VK_FALSE otherwise
739ece0e981ee4a5ad2572d146a89fc64d699d79f36Chris Forbesstatic bool SetSparseMemBinding(layer_data *dev_data, MEM_BINDING binding, uint64_t handle, VulkanObjectType type) {
7403251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = VK_FALSE;
7415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Handle NULL case separately, just clear previous binding & decrement reference
742f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis    if (binding.mem == VK_NULL_HANDLE) {
743f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        // TODO : This should cause the range of the resource to be unbound according to spec
7445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
745f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        BINDABLE *mem_binding = GetObjectMemBinding(dev_data, handle, type);
746f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        assert(mem_binding);
747f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        assert(mem_binding->sparse);
7489a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, binding.mem);
749f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis        if (mem_info) {
750f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis            mem_info->obj_bindings.insert({handle, type});
7512e415b757c1e43fda35311aad026af8d5c96681cTobin Ehlis            // Need to set mem binding for this object
752f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis            mem_binding->sparse_bindings.insert(binding);
7535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7553251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
756caf05e0db4959ae196ab34b024f352d9c0326870Tobin Ehlis}
757caf05e0db4959ae196ab34b024f352d9c0326870Tobin Ehlis
7585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// SPIRV utility functions
7595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic void build_def_index(shader_module *module) {
7605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *module) {
7615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        switch (insn.opcode()) {
762cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Types
763cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeVoid:
764cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeBool:
765cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeInt:
766cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeFloat:
767cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeVector:
768cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeMatrix:
769cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeImage:
770cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeSampler:
771cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeSampledImage:
772cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeArray:
773cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeRuntimeArray:
774cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeStruct:
775cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeOpaque:
776cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypePointer:
777cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeFunction:
778cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeEvent:
779cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeDeviceEvent:
780cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeReserveId:
781cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeQueue:
782cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypePipe:
783cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                module->def_index[insn.word(1)] = insn.offset();
784cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
7855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
786cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Fixed constants
787cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstantTrue:
788cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstantFalse:
789cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstant:
790cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstantComposite:
791cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstantSampler:
792cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpConstantNull:
793cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                module->def_index[insn.word(2)] = insn.offset();
794cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
7955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
796cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Specialization constants
797cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpSpecConstantTrue:
798cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpSpecConstantFalse:
799cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpSpecConstant:
800cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpSpecConstantComposite:
801cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpSpecConstantOp:
802cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                module->def_index[insn.word(2)] = insn.offset();
803cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
8045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
805cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Variables
806cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpVariable:
807cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                module->def_index[insn.word(2)] = insn.offset();
808cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
8095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
810cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Functions
811cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpFunction:
812cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                module->def_index[insn.word(2)] = insn.offset();
813cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
8145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
815cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
816cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // We don't care about any other defs for now.
817cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
8185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
8215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic spirv_inst_iter find_entrypoint(shader_module *src, char const *name, VkShaderStageFlagBits stageBits) {
8235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
8245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpEntryPoint) {
8255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            auto entrypointName = (char const *)&insn.word(3);
8265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            auto entrypointStageBits = 1u << insn.word(1);
8275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!strcmp(entrypointName, name) && (entrypointStageBits & stageBits)) {
8295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return insn;
8305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
8315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return src->end();
8355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
8365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic char const *storage_class_name(unsigned sc) {
8385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (sc) {
839cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassInput:
840cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "input";
841cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassOutput:
842cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "output";
843cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassUniformConstant:
844cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "const uniform";
845cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassUniform:
846cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "uniform";
847cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassWorkgroup:
848cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "workgroup local";
849cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassCrossWorkgroup:
850cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "workgroup global";
851cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassPrivate:
852cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "private global";
853cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassFunction:
854cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "function";
855cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassGeneric:
856cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "generic";
857cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassAtomicCounter:
858cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "atomic counter";
859cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassImage:
860cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "image";
861cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::StorageClassPushConstant:
862cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "push constant";
863cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
864cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return "unknown";
8655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
8675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
86825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// Get the value of an integral constant
8695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisunsigned get_constant_value(shader_module const *src, unsigned id) {
8705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto value = src->get_def(id);
8715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(value != src->end());
8725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (value.opcode() != spv::OpConstant) {
87425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // TODO: Either ensure that the specialization transform is already performed on a module we're
87525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        //       considering here, OR -- specialize on the fly now.
8765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return 1;
8775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return value.word(3);
8805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
8815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8829ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbesstatic void describe_type_inner(std::ostringstream &ss, shader_module const *src, unsigned type) {
8835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto insn = src->get_def(type);
8845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(insn != src->end());
8855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (insn.opcode()) {
887cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeBool:
888cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "bool";
889cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
890cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeInt:
891cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << (insn.word(3) ? 's' : 'u') << "int" << insn.word(2);
892cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
893cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeFloat:
894cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "float" << insn.word(2);
895cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
896cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeVector:
897cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "vec" << insn.word(3) << " of ";
898cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            describe_type_inner(ss, src, insn.word(2));
899cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
900cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeMatrix:
901cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "mat" << insn.word(3) << " of ";
902cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            describe_type_inner(ss, src, insn.word(2));
903cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
904cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeArray:
905cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "arr[" << get_constant_value(src, insn.word(3)) << "] of ";
906cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            describe_type_inner(ss, src, insn.word(2));
907cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
908cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypePointer:
909cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "ptr to " << storage_class_name(insn.word(2)) << " ";
910cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            describe_type_inner(ss, src, insn.word(3));
911cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
912cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeStruct: {
913cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "struct of (";
914cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            for (unsigned i = 2; i < insn.len(); i++) {
915cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                describe_type_inner(ss, src, insn.word(i));
916cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (i == insn.len() - 1) {
917cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    ss << ")";
918cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                } else {
919cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    ss << ", ";
920cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
9219ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes            }
922cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
9235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
924cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeSampler:
925cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "sampler";
926cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
927cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeSampledImage:
928cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "sampler+";
929cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            describe_type_inner(ss, src, insn.word(2));
930cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
931cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeImage:
932cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "image(dim=" << insn.word(3) << ", sampled=" << insn.word(7) << ")";
933cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
934cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
935cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            ss << "oddtype";
936cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
9375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
9395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9409ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbesstatic std::string describe_type(shader_module const *src, unsigned type) {
9419ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes    std::ostringstream ss;
9429ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes    describe_type_inner(ss, src, type);
9439ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes    return ss.str();
9449ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes}
9459ccb7b1342fd1a901f1ae0d202721a50d2c227f9Chris Forbes
946bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool is_narrow_numeric_type(spirv_inst_iter type) {
947cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (type.opcode() != spv::OpTypeInt && type.opcode() != spv::OpTypeFloat) return false;
94837576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes    return type.word(2) < 64;
94937576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes}
95037576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes
951bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool types_match(shader_module const *a, shader_module const *b, unsigned a_type, unsigned b_type, bool a_arrayed,
952bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        bool b_arrayed, bool relaxed) {
95325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Walk two type trees together, and complain about differences
9545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto a_insn = a->get_def(a_type);
9555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto b_insn = b->get_def(b_type);
9565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(a_insn != a->end());
9575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(b_insn != b->end());
9585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9597c755c8aca6857046df9516d8336416165969cb9Chris Forbes    if (a_arrayed && a_insn.opcode() == spv::OpTypeArray) {
96037576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes        return types_match(a, b, a_insn.word(2), b_type, false, b_arrayed, relaxed);
9617c755c8aca6857046df9516d8336416165969cb9Chris Forbes    }
9627c755c8aca6857046df9516d8336416165969cb9Chris Forbes
9635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (b_arrayed && b_insn.opcode() == spv::OpTypeArray) {
96425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // We probably just found the extra level of arrayness in b_type: compare the type inside it to a_type
96537576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes        return types_match(a, b, a_type, b_insn.word(2), a_arrayed, false, relaxed);
96637576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes    }
96737576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes
96837576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes    if (a_insn.opcode() == spv::OpTypeVector && relaxed && is_narrow_numeric_type(b_insn)) {
96937576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes        return types_match(a, b, a_insn.word(2), b_type, a_arrayed, b_arrayed, false);
9705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (a_insn.opcode() != b_insn.opcode()) {
9735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return false;
9745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9767c755c8aca6857046df9516d8336416165969cb9Chris Forbes    if (a_insn.opcode() == spv::OpTypePointer) {
97725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Match on pointee type. storage class is expected to differ
97837576f9c5ccc190c53a1c10baf383d77c3c6d476Chris Forbes        return types_match(a, b, a_insn.word(3), b_insn.word(3), a_arrayed, b_arrayed, relaxed);
9797c755c8aca6857046df9516d8336416165969cb9Chris Forbes    }
9807c755c8aca6857046df9516d8336416165969cb9Chris Forbes
9817c755c8aca6857046df9516d8336416165969cb9Chris Forbes    if (a_arrayed || b_arrayed) {
98225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // If we havent resolved array-of-verts by here, we're not going to.
9837c755c8aca6857046df9516d8336416165969cb9Chris Forbes        return false;
9847c755c8aca6857046df9516d8336416165969cb9Chris Forbes    }
9857c755c8aca6857046df9516d8336416165969cb9Chris Forbes
9865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (a_insn.opcode()) {
987cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeBool:
988cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return true;
989cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeInt:
990cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on width, signedness
991cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return a_insn.word(2) == b_insn.word(2) && a_insn.word(3) == b_insn.word(3);
992cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeFloat:
993cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on width
994cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return a_insn.word(2) == b_insn.word(2);
995cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeVector:
996cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on element type, count.
997cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (!types_match(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false)) return false;
998cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (relaxed && is_narrow_numeric_type(a->get_def(a_insn.word(2)))) {
999cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return a_insn.word(3) >= b_insn.word(3);
1000cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else {
1001cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return a_insn.word(3) == b_insn.word(3);
10025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
1003cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeMatrix:
1004cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on element type, count.
1005cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return types_match(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false) &&
1006cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                   a_insn.word(3) == b_insn.word(3);
1007cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeArray:
1008cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on element type, count. these all have the same layout. we don't get here if b_arrayed. This differs from
1009cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // vector & matrix types in that the array size is the id of a constant instruction, * not a literal within OpTypeArray
1010cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return types_match(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false) &&
1011cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                   get_constant_value(a, a_insn.word(3)) == get_constant_value(b, b_insn.word(3));
1012cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeStruct:
1013cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Match on all element types
1014cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            {
1015cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (a_insn.len() != b_insn.len()) {
1016cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    return false;  // Structs cannot match if member counts differ
1017cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
10185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1019cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                for (unsigned i = 2; i < a_insn.len(); i++) {
1020cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    if (!types_match(a, b, a_insn.word(i), b_insn.word(i), a_arrayed, b_arrayed, false)) {
1021cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return false;
1022cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    }
1023cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
1024cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski
1025cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return true;
1026cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
1027cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1028cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Remaining types are CLisms, or may not appear in the interfaces we are interested in. Just claim no match.
1029cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return false;
10305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
10325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10332c81be6aa02b10d9e225329977fa108ceda890a2Chris Forbesstatic unsigned value_or_default(std::unordered_map<unsigned, unsigned> const &map, unsigned id, unsigned def) {
10345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto it = map.find(id);
10355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (it == map.end())
10365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return def;
10375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    else
10385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return it->second;
10395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
10405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic unsigned get_locations_consumed_by_type(shader_module const *src, unsigned type, bool strip_array_level) {
10425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto insn = src->get_def(type);
10435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(insn != src->end());
10445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (insn.opcode()) {
1046cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypePointer:
1047cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // See through the ptr -- this is only ever at the toplevel for graphics shaders we're never actually passing
1048cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // pointers around.
1049cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_locations_consumed_by_type(src, insn.word(3), strip_array_level);
1050cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeArray:
1051cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (strip_array_level) {
1052cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return get_locations_consumed_by_type(src, insn.word(2), false);
1053cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else {
1054cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return get_constant_value(src, insn.word(3)) * get_locations_consumed_by_type(src, insn.word(2), false);
1055cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
1056cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeMatrix:
1057cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Num locations is the dimension * element size
1058cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return insn.word(3) * get_locations_consumed_by_type(src, insn.word(2), false);
1059cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeVector: {
1060cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            auto scalar_type = src->get_def(insn.word(2));
1061cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            auto bit_width =
1062cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                (scalar_type.opcode() == spv::OpTypeInt || scalar_type.opcode() == spv::OpTypeFloat) ? scalar_type.word(2) : 32;
1063cc52143fc093e1e62d2dacc4abc3966e04b6f6d6Chris Forbes
1064cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Locations are 128-bit wide; 3- and 4-component vectors of 64 bit types require two.
1065cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return (bit_width * insn.word(3) + 127) / 128;
1066cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
1067cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1068cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Everything else is just 1.
1069cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return 1;
10705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1071cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // TODO: extend to handle 64bit scalar types, whose vectors may need multiple locations.
10725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
10745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1075c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbesstatic unsigned get_locations_consumed_by_format(VkFormat format) {
1076c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes    switch (format) {
1077cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64A64_SFLOAT:
1078cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64A64_SINT:
1079cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64A64_UINT:
1080cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64_SFLOAT:
1081cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64_SINT:
1082cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case VK_FORMAT_R64G64B64_UINT:
1083cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return 2;
1084cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1085cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return 1;
1086c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes    }
1087c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes}
1088c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes
10895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlistypedef std::pair<unsigned, unsigned> location_t;
10905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlistypedef std::pair<unsigned, unsigned> descriptor_slot_t;
10915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstruct interface_var {
10935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t id;
10945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t type_id;
10955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t offset;
1096b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes    bool is_patch;
1097fff9393206f66a154438e16fa0562c989f425498Chris Forbes    bool is_block_member;
1098b0436668e6594b8528e96de7bed208399fb2431dChris Forbes    bool is_relaxed_precision;
109925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // TODO: collect the name, too? Isn't required to be present.
11005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis};
11015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1102031261d21af8907953dd763398ce9a23e65b8749Chris Forbesstruct shader_stage_attributes {
1103031261d21af8907953dd763398ce9a23e65b8749Chris Forbes    char const *const name;
1104031261d21af8907953dd763398ce9a23e65b8749Chris Forbes    bool arrayed_input;
1105031261d21af8907953dd763398ce9a23e65b8749Chris Forbes    bool arrayed_output;
1106031261d21af8907953dd763398ce9a23e65b8749Chris Forbes};
1107031261d21af8907953dd763398ce9a23e65b8749Chris Forbes
1108031261d21af8907953dd763398ce9a23e65b8749Chris Forbesstatic shader_stage_attributes shader_stage_attribs[] = {
1109bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    {"vertex shader", false, false},  {"tessellation control shader", true, true}, {"tessellation evaluation shader", true, false},
1110bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    {"geometry shader", true, false}, {"fragment shader", false, false},
1111031261d21af8907953dd763398ce9a23e65b8749Chris Forbes};
1112031261d21af8907953dd763398ce9a23e65b8749Chris Forbes
11135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic spirv_inst_iter get_struct_type(shader_module const *src, spirv_inst_iter def, bool is_array_of_verts) {
11145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while (true) {
11155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (def.opcode() == spv::OpTypePointer) {
11165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            def = src->get_def(def.word(3));
11175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (def.opcode() == spv::OpTypeArray && is_array_of_verts) {
11185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            def = src->get_def(def.word(2));
11195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            is_array_of_verts = false;
11205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (def.opcode() == spv::OpTypeStruct) {
11215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return def;
11225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
11235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return src->end();
11245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
11255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
11265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
11275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1128bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic void collect_interface_block_members(shader_module const *src, std::map<location_t, interface_var> *out,
11295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                            std::unordered_map<unsigned, unsigned> const &blocks, bool is_array_of_verts,
1130b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes                                            uint32_t id, uint32_t type_id, bool is_patch) {
113125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Walk down the type_id presented, trying to determine whether it's actually an interface block.
1132031261d21af8907953dd763398ce9a23e65b8749Chris Forbes    auto type = get_struct_type(src, src->get_def(type_id), is_array_of_verts && !is_patch);
11335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (type == src->end() || blocks.find(type.word(1)) == blocks.end()) {
113425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // This isn't an interface block.
11355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return;
11365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
11375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> member_components;
11395b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes    std::unordered_map<unsigned, unsigned> member_relaxed_precision;
11405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
114125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Walk all the OpMemberDecorate for type's result id -- first pass, collect components.
11425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
11435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
11445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned member_index = insn.word(2);
11455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(3) == spv::DecorationComponent) {
11475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                unsigned component = insn.word(4);
11485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                member_components[member_index] = component;
11495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
11505b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes
11515b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes            if (insn.word(3) == spv::DecorationRelaxedPrecision) {
11525b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes                member_relaxed_precision[member_index] = 1;
11535b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes            }
11545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
11555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
11565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
115725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Second pass -- produce the output, from Location decorations
11585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
11595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
11605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned member_index = insn.word(2);
11615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned member_type_id = type.word(2 + member_index);
11625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(3) == spv::DecorationLocation) {
11645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                unsigned location = insn.word(4);
11655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                unsigned num_locations = get_locations_consumed_by_type(src, member_type_id, false);
11665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                auto component_it = member_components.find(member_index);
11675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                unsigned component = component_it == member_components.end() ? 0 : component_it->second;
11685b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes                bool is_relaxed_precision = member_relaxed_precision.find(member_index) != member_relaxed_precision.end();
11695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                for (unsigned int offset = 0; offset < num_locations; offset++) {
1171b0436668e6594b8528e96de7bed208399fb2431dChris Forbes                    interface_var v = {};
11725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.id = id;
117325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski                    // TODO: member index in interface_var too?
11745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.type_id = member_type_id;
11755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.offset = offset;
1176b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes                    v.is_patch = is_patch;
1177fff9393206f66a154438e16fa0562c989f425498Chris Forbes                    v.is_block_member = true;
11785b9f2047984d6ca10d89a35ba8a2ebe0fa6bff69Chris Forbes                    v.is_relaxed_precision = is_relaxed_precision;
11793a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes                    (*out)[std::make_pair(location + offset, component)] = v;
11805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
11815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
11825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
11835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
11845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
11855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1186bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic std::map<location_t, interface_var> collect_interface_by_location(shader_module const *src, spirv_inst_iter entrypoint,
1187bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                         spv::StorageClass sinterface, bool is_array_of_verts) {
11885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> var_locations;
11895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> var_builtins;
11905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> var_components;
11915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> blocks;
1192b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes    std::unordered_map<unsigned, unsigned> var_patch;
1193b0436668e6594b8528e96de7bed208399fb2431dChris Forbes    std::unordered_map<unsigned, unsigned> var_relaxed_precision;
11945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
119625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // We consider two interface models: SSO rendezvous-by-location, and builtins. Complain about anything that
119725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // fits neither model.
11985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpDecorate) {
11995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationLocation) {
12005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                var_locations[insn.word(1)] = insn.word(3);
12015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
12025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationBuiltIn) {
12045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                var_builtins[insn.word(1)] = insn.word(3);
12055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
12065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationComponent) {
12085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                var_components[insn.word(1)] = insn.word(3);
12095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
12105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationBlock) {
12125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                blocks[insn.word(1)] = 1;
12135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
1214b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes
1215b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes            if (insn.word(2) == spv::DecorationPatch) {
1216b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes                var_patch[insn.word(1)] = 1;
1217b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes            }
1218b0436668e6594b8528e96de7bed208399fb2431dChris Forbes
1219b0436668e6594b8528e96de7bed208399fb2431dChris Forbes            if (insn.word(2) == spv::DecorationRelaxedPrecision) {
1220b0436668e6594b8528e96de7bed208399fb2431dChris Forbes                var_relaxed_precision[insn.word(1)] = 1;
1221b0436668e6594b8528e96de7bed208399fb2431dChris Forbes            }
12225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
12235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
12245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
122525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // TODO: handle grouped decorations
122625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // TODO: handle index=1 dual source outputs from FS -- two vars will have the same location, and we DON'T want to clobber.
12275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
122825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Find the end of the entrypoint's name string. additional zero bytes follow the actual null terminator, to fill out the
122925002b75574f762c62b1a00a595bab04ebb25452Mark 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.
1230c15b801a6e1a5dd5eed09e689aecdde7c4a90a5bMichael Mc Donnell    uint32_t word = 3;
12315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while (entrypoint.word(word) & 0xff000000u) {
12325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        ++word;
12335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
12345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    ++word;
12355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12363a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    std::map<location_t, interface_var> out;
12373a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
12385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (; word < entrypoint.len(); word++) {
12395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto insn = src->get_def(entrypoint.word(word));
12405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        assert(insn != src->end());
12415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        assert(insn.opcode() == spv::OpVariable);
12425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12431d5109d5e0dcc530b27e632e73e1be5e12a28dcdJamie Madill        if (insn.word(3) == static_cast<uint32_t>(sinterface)) {
12445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned id = insn.word(2);
12455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned type = insn.word(1);
12465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            int location = value_or_default(var_locations, id, -1);
12485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            int builtin = value_or_default(var_builtins, id, -1);
1249cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            unsigned component = value_or_default(var_components, id, 0);  // Unspecified is OK, is 0
1250b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes            bool is_patch = var_patch.find(id) != var_patch.end();
1251b0436668e6594b8528e96de7bed208399fb2431dChris Forbes            bool is_relaxed_precision = var_relaxed_precision.find(id) != var_relaxed_precision.end();
12525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
125325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // All variables and interface block members in the Input or Output storage classes must be decorated with either
125425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // a builtin or an explicit location.
125525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            //
125625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // TODO: integrate the interface block support here. For now, don't complain -- a valid SPIRV module will only hit
125725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // this path for the interface block case, as the individual members of the type are decorated, rather than
125825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // variable declarations.
12595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
12605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (location != -1) {
126125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski                // A user-defined interface variable, with a location. Where a variable occupied multiple locations, emit
126225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski                // one result for each.
12637c755c8aca6857046df9516d8336416165969cb9Chris Forbes                unsigned num_locations = get_locations_consumed_by_type(src, type, is_array_of_verts && !is_patch);
12645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                for (unsigned int offset = 0; offset < num_locations; offset++) {
1265b0436668e6594b8528e96de7bed208399fb2431dChris Forbes                    interface_var v = {};
12665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.id = id;
12675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.type_id = type;
12685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    v.offset = offset;
1269b934cb26db50b965da46ca3e3f006d5a93478f71Chris Forbes                    v.is_patch = is_patch;
1270b0436668e6594b8528e96de7bed208399fb2431dChris Forbes                    v.is_relaxed_precision = is_relaxed_precision;
12715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    out[std::make_pair(location + offset, component)] = v;
12725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
12735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else if (builtin == -1) {
127425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski                // An interface block instance
12753a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes                collect_interface_block_members(src, &out, blocks, is_array_of_verts, id, type, is_patch);
12765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
12775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
12785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
12793a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
12803a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    return out;
12815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
12825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
128312b7fc342b53fbdd399aae4a85959e37685936acChris Forbesstatic vector<std::pair<uint32_t, interface_var>> collect_interface_by_input_attachment_index(
128412b7fc342b53fbdd399aae4a85959e37685936acChris Forbes    shader_module const *src, std::unordered_set<uint32_t> const &accessible_ids) {
12853a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    std::vector<std::pair<uint32_t, interface_var>> out;
1286745d49409296f060402b57950384caadb636a2b2Chris Forbes
1287745d49409296f060402b57950384caadb636a2b2Chris Forbes    for (auto insn : *src) {
1288745d49409296f060402b57950384caadb636a2b2Chris Forbes        if (insn.opcode() == spv::OpDecorate) {
1289745d49409296f060402b57950384caadb636a2b2Chris Forbes            if (insn.word(2) == spv::DecorationInputAttachmentIndex) {
1290745d49409296f060402b57950384caadb636a2b2Chris Forbes                auto attachment_index = insn.word(3);
1291745d49409296f060402b57950384caadb636a2b2Chris Forbes                auto id = insn.word(1);
1292745d49409296f060402b57950384caadb636a2b2Chris Forbes
1293745d49409296f060402b57950384caadb636a2b2Chris Forbes                if (accessible_ids.count(id)) {
1294745d49409296f060402b57950384caadb636a2b2Chris Forbes                    auto def = src->get_def(id);
1295745d49409296f060402b57950384caadb636a2b2Chris Forbes                    assert(def != src->end());
1296745d49409296f060402b57950384caadb636a2b2Chris Forbes
1297745d49409296f060402b57950384caadb636a2b2Chris Forbes                    if (def.opcode() == spv::OpVariable && insn.word(3) == spv::StorageClassUniformConstant) {
1298e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                        auto num_locations = get_locations_consumed_by_type(src, def.word(1), false);
1299e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                        for (unsigned int offset = 0; offset < num_locations; offset++) {
1300b0436668e6594b8528e96de7bed208399fb2431dChris Forbes                            interface_var v = {};
1301e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                            v.id = id;
1302e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                            v.type_id = def.word(1);
1303e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                            v.offset = offset;
1304e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                            out.emplace_back(attachment_index + offset, v);
1305e0cc9b3441a24e4fbd2b4e0a9d163dab2140264aChris Forbes                        }
1306745d49409296f060402b57950384caadb636a2b2Chris Forbes                    }
1307745d49409296f060402b57950384caadb636a2b2Chris Forbes                }
1308745d49409296f060402b57950384caadb636a2b2Chris Forbes            }
1309745d49409296f060402b57950384caadb636a2b2Chris Forbes        }
1310745d49409296f060402b57950384caadb636a2b2Chris Forbes    }
13113a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
13123a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    return out;
1313745d49409296f060402b57950384caadb636a2b2Chris Forbes}
1314745d49409296f060402b57950384caadb636a2b2Chris Forbes
1315cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskistatic std::vector<std::pair<descriptor_slot_t, interface_var>> collect_interface_by_descriptor_slot(
1316cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    debug_report_data *report_data, shader_module const *src, std::unordered_set<uint32_t> const &accessible_ids) {
13175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> var_sets;
13185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<unsigned, unsigned> var_bindings;
13195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
132125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // All variables in the Uniform or UniformConstant storage classes are required to be decorated with both
132225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // DecorationDescriptorSet and DecorationBinding.
13235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpDecorate) {
13245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationDescriptorSet) {
13255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                var_sets[insn.word(1)] = insn.word(3);
13265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
13275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(2) == spv::DecorationBinding) {
13295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                var_bindings[insn.word(1)] = insn.word(3);
13305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
13315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
13325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
13335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13343a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    std::vector<std::pair<descriptor_slot_t, interface_var>> out;
13353a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
13365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto id : accessible_ids) {
13375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto insn = src->get_def(id);
13385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        assert(insn != src->end());
13395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpVariable &&
13415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            (insn.word(3) == spv::StorageClassUniform || insn.word(3) == spv::StorageClassUniformConstant)) {
13425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned set = value_or_default(var_sets, insn.word(2), 0);
13435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned binding = value_or_default(var_bindings, insn.word(2), 0);
13445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1345b0436668e6594b8528e96de7bed208399fb2431dChris Forbes            interface_var v = {};
13465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            v.id = insn.word(2);
13475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            v.type_id = insn.word(1);
1348cefd4dd8e03c5dae11a05d04a03cb856190358e0Chris Forbes            out.emplace_back(std::make_pair(set, binding), v);
13495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
13505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
13513a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
13523a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    return out;
13535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
13545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1355edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_interface_between_stages(debug_report_data *report_data, shader_module const *producer,
1356031261d21af8907953dd763398ce9a23e65b8749Chris Forbes                                              spirv_inst_iter producer_entrypoint, shader_stage_attributes const *producer_stage,
13575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                              shader_module const *consumer, spirv_inst_iter consumer_entrypoint,
1358031261d21af8907953dd763398ce9a23e65b8749Chris Forbes                                              shader_stage_attributes const *consumer_stage) {
13591b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    bool skip = false;
13605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1361bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto outputs =
1362bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        collect_interface_by_location(producer, producer_entrypoint, spv::StorageClassOutput, producer_stage->arrayed_output);
1363bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto inputs =
1364bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        collect_interface_by_location(consumer, consumer_entrypoint, spv::StorageClassInput, consumer_stage->arrayed_input);
13655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto a_it = outputs.begin();
13675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto b_it = inputs.begin();
13685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
136925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Maps sorted by key (location); walk them together to find mismatches
13705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while ((outputs.size() > 0 && a_it != outputs.end()) || (inputs.size() && b_it != inputs.end())) {
13715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        bool a_at_end = outputs.size() == 0 || a_it == outputs.end();
13725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        bool b_at_end = inputs.size() == 0 || b_it == inputs.end();
13735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto a_first = a_at_end ? std::make_pair(0u, 0u) : a_it->first;
13745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto b_first = b_at_end ? std::make_pair(0u, 0u) : b_it->first;
13755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
13765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (b_at_end || ((!a_at_end) && (a_first < b_first))) {
13771b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
13781b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            __LINE__, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",
13791b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            "%s writes to output location %u.%u which is not consumed by %s", producer_stage->name, a_first.first,
13801b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            a_first.second, consumer_stage->name);
13815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            a_it++;
13825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (a_at_end || a_first > b_first) {
13831b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
13841b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "%s consumes input location %u.%u which is not written by %s",
13851b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            consumer_stage->name, b_first.first, b_first.second, producer_stage->name);
13865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            b_it++;
13875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
1388fff9393206f66a154438e16fa0562c989f425498Chris Forbes            // subtleties of arrayed interfaces:
1389fff9393206f66a154438e16fa0562c989f425498Chris Forbes            // - if is_patch, then the member is not arrayed, even though the interface may be.
1390fff9393206f66a154438e16fa0562c989f425498Chris Forbes            // - if is_block_member, then the extra array level of an arrayed interface is not
1391fff9393206f66a154438e16fa0562c989f425498Chris Forbes            //   expressed in the member type -- it's expressed in the block type.
13920f44c68c2575ba2fc83d8c8f2f5ea09548f40686Chris Forbes            if (!types_match(producer, consumer, a_it->second.type_id, b_it->second.type_id,
1393fff9393206f66a154438e16fa0562c989f425498Chris Forbes                             producer_stage->arrayed_output && !a_it->second.is_patch && !a_it->second.is_block_member,
1394bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             consumer_stage->arrayed_input && !b_it->second.is_patch && !b_it->second.is_block_member, true)) {
13951b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
13961b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC", "Type mismatch on location %u.%u: '%s' vs '%s'",
13971b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                a_first.first, a_first.second, describe_type(producer, a_it->second.type_id).c_str(),
13981b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                describe_type(consumer, b_it->second.type_id).c_str());
13995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
14000f44c68c2575ba2fc83d8c8f2f5ea09548f40686Chris Forbes            if (a_it->second.is_patch != b_it->second.is_patch) {
14011b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
14021b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
14031b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                "Decoration mismatch on location %u.%u: is per-%s in %s stage but "
14041b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                "per-%s in %s stage",
14051b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                a_first.first, a_first.second, a_it->second.is_patch ? "patch" : "vertex", producer_stage->name,
14061b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                b_it->second.is_patch ? "patch" : "vertex", consumer_stage->name);
14070f44c68c2575ba2fc83d8c8f2f5ea09548f40686Chris Forbes            }
140817c6bacf91ac671cb33212071b87b8ea782812f5Chris Forbes            if (a_it->second.is_relaxed_precision != b_it->second.is_relaxed_precision) {
14091b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
14101b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
14111b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                "Decoration mismatch on location %u.%u: %s and %s stages differ in precision", a_first.first,
14121b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                a_first.second, producer_stage->name, consumer_stage->name);
141317c6bacf91ac671cb33212071b87b8ea782812f5Chris Forbes            }
14145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            a_it++;
14155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            b_it++;
14165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
14175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
14185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14191b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return skip;
14205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
14215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisenum FORMAT_TYPE {
1423f0fdde7692ffd5175435cc3bf3412b8468054f38Chris Forbes    FORMAT_TYPE_FLOAT = 1,  // UNORM, SNORM, FLOAT, USCALED, SSCALED, SRGB -- anything we consider float in the shader
1424f0fdde7692ffd5175435cc3bf3412b8468054f38Chris Forbes    FORMAT_TYPE_SINT = 2,
1425f0fdde7692ffd5175435cc3bf3412b8468054f38Chris Forbes    FORMAT_TYPE_UINT = 4,
14265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis};
14275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic unsigned get_format_type(VkFormat fmt) {
142928f7140700a1624f4836243204237c80645e0fb9Chris Forbes    if (FormatIsSInt(fmt))
143028f7140700a1624f4836243204237c80645e0fb9Chris Forbes        return FORMAT_TYPE_SINT;
143128f7140700a1624f4836243204237c80645e0fb9Chris Forbes    if (FormatIsUInt(fmt))
143228f7140700a1624f4836243204237c80645e0fb9Chris Forbes        return FORMAT_TYPE_UINT;
143328f7140700a1624f4836243204237c80645e0fb9Chris Forbes    if (FormatIsDepthAndStencil(fmt))
143428f7140700a1624f4836243204237c80645e0fb9Chris Forbes        return FORMAT_TYPE_FLOAT | FORMAT_TYPE_UINT;
143528f7140700a1624f4836243204237c80645e0fb9Chris Forbes    if (fmt == VK_FORMAT_UNDEFINED)
143628f7140700a1624f4836243204237c80645e0fb9Chris Forbes        return 0;
143728f7140700a1624f4836243204237c80645e0fb9Chris Forbes    // everything else -- UNORM/SNORM/FLOAT/USCALED/SSCALED is all float in the shader.
143828f7140700a1624f4836243204237c80645e0fb9Chris Forbes    return FORMAT_TYPE_FLOAT;
14395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
14405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
144125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// characterizes a SPIR-V type appearing in an interface to a FF stage, for comparison to a VkFormat's characterization above.
14425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic unsigned get_fundamental_type(shader_module const *src, unsigned type) {
14435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto insn = src->get_def(type);
14445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(insn != src->end());
14455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (insn.opcode()) {
1447cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeInt:
1448cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return insn.word(3) ? FORMAT_TYPE_SINT : FORMAT_TYPE_UINT;
1449cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeFloat:
1450cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return FORMAT_TYPE_FLOAT;
1451cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeVector:
1452cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_fundamental_type(src, insn.word(2));
1453cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeMatrix:
1454cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_fundamental_type(src, insn.word(2));
1455cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeArray:
1456cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_fundamental_type(src, insn.word(2));
1457cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypePointer:
1458cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_fundamental_type(src, insn.word(3));
1459cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeImage:
1460cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return get_fundamental_type(src, insn.word(2));
1461cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski
1462cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
1463f0fdde7692ffd5175435cc3bf3412b8468054f38Chris Forbes            return 0;
14645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
14655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
14665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic uint32_t get_shader_stage_id(VkShaderStageFlagBits stage) {
14688e88ad80aacad2085e76016e7bb29d243ce7f7b6Chris Forbes    uint32_t bit_pos = uint32_t(u_ffs(stage));
14695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return bit_pos - 1;
14705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
14715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1472edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_vi_consistency(debug_report_data *report_data, VkPipelineVertexInputStateCreateInfo const *vi) {
147325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Walk the binding descriptions, which describe the step rate and stride of each vertex buffer.  Each binding should
147425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // be specified only once.
14755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_map<uint32_t, VkVertexInputBindingDescription const *> bindings;
14761b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    bool skip = false;
14775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (unsigned i = 0; i < vi->vertexBindingDescriptionCount; i++) {
14795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto desc = &vi->pVertexBindingDescriptions[i];
14805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto &binding = bindings[desc->binding];
14815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (binding) {
1482315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            // TODO: VALIDATION_ERROR_096005cc perhaps?
14831b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
1484bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        SHADER_CHECKER_INCONSISTENT_VI, "SC", "Duplicate vertex input binding descriptions for binding %d",
14851b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                        desc->binding);
14865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
14875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            binding = desc;
14885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
14895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
14905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14911b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return skip;
14925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
14935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1494edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_vi_against_vs_inputs(debug_report_data *report_data, VkPipelineVertexInputStateCreateInfo const *vi,
14955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                          shader_module const *vs, spirv_inst_iter entrypoint) {
14961b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    bool skip = false;
14975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
14983a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    auto inputs = collect_interface_by_location(vs, entrypoint, spv::StorageClassInput, false);
14995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
150025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Build index by location
15015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::map<uint32_t, VkVertexInputAttributeDescription const *> attribs;
15025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (vi) {
1503c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes        for (unsigned i = 0; i < vi->vertexAttributeDescriptionCount; i++) {
1504c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes            auto num_locations = get_locations_consumed_by_format(vi->pVertexAttributeDescriptions[i].format);
1505c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes            for (auto j = 0u; j < num_locations; j++) {
1506c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes                attribs[vi->pVertexAttributeDescriptions[i].location + j] = &vi->pVertexAttributeDescriptions[i];
1507c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes            }
1508c7255e92ea81e8639dc21388ec2a959bd63319c7Chris Forbes        }
15095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
15105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto it_a = attribs.begin();
15125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto it_b = inputs.begin();
15131730e0dd28b3abc660b4e4704cf6d414f7fd4ad6Chris Forbes    bool used = false;
15145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while ((attribs.size() > 0 && it_a != attribs.end()) || (inputs.size() > 0 && it_b != inputs.end())) {
15165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        bool a_at_end = attribs.size() == 0 || it_a == attribs.end();
15175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        bool b_at_end = inputs.size() == 0 || it_b == inputs.end();
15185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto a_first = a_at_end ? 0 : it_a->first;
15195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto b_first = b_at_end ? 0 : it_b->first.first;
15205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!a_at_end && (b_at_end || a_first < b_first)) {
15215b9ab1fb8720c30edfbe8dd974e2364425471ad5Mark Lobodzinski            if (!used && log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
15225b9ab1fb8720c30edfbe8dd974e2364425471ad5Mark Lobodzinski                                 0, __LINE__, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",
1523bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                 "Vertex attribute at location %d not consumed by vertex shader", a_first)) {
15241b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                skip = true;
15255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
15261730e0dd28b3abc660b4e4704cf6d414f7fd4ad6Chris Forbes            used = false;
15275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            it_a++;
15285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (!b_at_end && (a_at_end || b_first < a_first)) {
15291b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
15301b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "Vertex shader consumes input at location %d but not provided",
15311b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            b_first);
15325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            it_b++;
15335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
15345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned attrib_type = get_format_type(it_a->second->format);
15355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            unsigned input_type = get_fundamental_type(vs, it_b->second.type_id);
15365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
153725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // Type checking
1538f0fdde7692ffd5175435cc3bf3412b8468054f38Chris Forbes            if (!(attrib_type & input_type)) {
15391b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
15401b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
15411b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                "Attribute type of `%s` at location %d does not match vertex shader input type of `%s`",
15421b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                string_VkFormat(it_a->second->format), a_first, describe_type(vs, it_b->second.type_id).c_str());
15435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
15445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
154525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // OK!
15461730e0dd28b3abc660b4e4704cf6d414f7fd4ad6Chris Forbes            used = true;
15475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            it_b++;
15485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
15495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
15505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15511b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return skip;
15525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
15535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1554edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_fs_outputs_against_render_pass(debug_report_data *report_data, shader_module const *fs,
15558da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis                                                    spirv_inst_iter entrypoint, VkRenderPassCreateInfo const *rpci,
15568da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis                                                    uint32_t subpass_index) {
1557025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes    std::map<uint32_t, VkFormat> color_attachments;
15588da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis    auto subpass = rpci->pSubpasses[subpass_index];
15598da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis    for (auto i = 0u; i < subpass.colorAttachmentCount; ++i) {
1560d9da90d92748c37962766868f8b0354637672c2aTobin Ehlis        uint32_t attachment = subpass.pColorAttachments[i].attachment;
1561cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (attachment == VK_ATTACHMENT_UNUSED) continue;
1562d9da90d92748c37962766868f8b0354637672c2aTobin Ehlis        if (rpci->pAttachments[attachment].format != VK_FORMAT_UNDEFINED) {
1563d9da90d92748c37962766868f8b0354637672c2aTobin Ehlis            color_attachments[i] = rpci->pAttachments[attachment].format;
1564025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes        }
1565025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes    }
1566025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes
15671b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    bool skip = false;
15685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
156925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // TODO: dual source blend index (spv::DecIndex, zero if not provided)
15705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
15713a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    auto outputs = collect_interface_by_location(fs, entrypoint, spv::StorageClassOutput, false);
15725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1573025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes    auto it_a = outputs.begin();
1574025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes    auto it_b = color_attachments.begin();
15755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
157625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Walk attachment list and outputs together
1577025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes
1578025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes    while ((outputs.size() > 0 && it_a != outputs.end()) || (color_attachments.size() > 0 && it_b != color_attachments.end())) {
1579025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes        bool a_at_end = outputs.size() == 0 || it_a == outputs.end();
1580025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes        bool b_at_end = color_attachments.size() == 0 || it_b == color_attachments.end();
15815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1582025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes        if (!a_at_end && (b_at_end || it_a->first.first < it_b->first)) {
15831b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
15841b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",
15851b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            "fragment shader writes to output location %d with no matching attachment", it_a->first.first);
1586025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            it_a++;
1587025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes        } else if (!b_at_end && (a_at_end || it_a->first.first > it_b->first)) {
15881b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
15891b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "Attachment %d not written by fragment shader", it_b->first);
1590025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            it_b++;
15915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
1592025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            unsigned output_type = get_fundamental_type(fs, it_a->second.type_id);
1593025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            unsigned att_type = get_format_type(it_b->second);
15945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
159525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // Type checking
1596f0fdde7692ffd5175435cc3bf3412b8468054f38Chris Forbes            if (!(output_type & att_type)) {
15971b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
15981b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
15991b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                "Attachment %d of type `%s` does not match fragment shader output type of `%s`", it_b->first,
16001b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                string_VkFormat(it_b->second), describe_type(fs, it_a->second.type_id).c_str());
16015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
16025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
160325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // OK!
1604025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            it_a++;
1605025e5113963305eff75601c96eac61d2c5b57e3cChris Forbes            it_b++;
16065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
16075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
16085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
16091b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return skip;
16105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
16115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
161225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// For some analyses, we need to know about all ids referenced by the static call tree of a particular entrypoint. This is
161325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// important for identifying the set of shader resources actually used by an entrypoint, for example.
161425002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// Note: we only explore parts of the image which might actually contain ids we care about for the above analyses.
161525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski//  - NOT the shader input/output interfaces.
161625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski//
161725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// TODO: The set of interesting opcodes here was determined by eyeballing the SPIRV spec. It might be worth
161825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// converting parts of this to be generated from the machine-readable spec instead.
16193a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbesstatic std::unordered_set<uint32_t> mark_accessible_ids(shader_module const *src, spirv_inst_iter entrypoint) {
16203a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    std::unordered_set<uint32_t> ids;
16215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::unordered_set<uint32_t> worklist;
16225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    worklist.insert(entrypoint.word(2));
16235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
16245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while (!worklist.empty()) {
16255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto id_iter = worklist.begin();
16265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto id = *id_iter;
16275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        worklist.erase(id_iter);
16285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
16295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto insn = src->get_def(id);
16305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn == src->end()) {
163125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // ID is something we didn't collect in build_def_index. that's OK -- we'll stumble across all kinds of things here
163225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski            // that we may not care about.
16335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            continue;
16345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
16355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
163625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Try to add to the output set
16375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!ids.insert(id).second) {
1638cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            continue;  // If we already saw this id, we don't want to walk it again.
16395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
16405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
16415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        switch (insn.opcode()) {
1642cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpFunction:
1643cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // Scan whole body of the function, enlisting anything interesting
1644cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                while (++insn, insn.opcode() != spv::OpFunctionEnd) {
1645cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    switch (insn.opcode()) {
1646cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpLoad:
1647cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicLoad:
1648cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicExchange:
1649cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicCompareExchange:
1650cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicCompareExchangeWeak:
1651cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicIIncrement:
1652cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicIDecrement:
1653cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicIAdd:
1654cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicISub:
1655cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicSMin:
1656cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicUMin:
1657cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicSMax:
1658cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicUMax:
1659cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicAnd:
1660cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicOr:
1661cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicXor:
1662cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            worklist.insert(insn.word(3));  // ptr
1663cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
1664cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpStore:
1665cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAtomicStore:
1666cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            worklist.insert(insn.word(1));  // ptr
1667cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
1668cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpAccessChain:
1669cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpInBoundsAccessChain:
1670cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            worklist.insert(insn.word(3));  // base ptr
1671cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
1672cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpSampledImage:
1673cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleImplicitLod:
1674cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleExplicitLod:
1675cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleDrefImplicitLod:
1676cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleDrefExplicitLod:
1677cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleProjImplicitLod:
1678cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleProjExplicitLod:
1679cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleProjDrefImplicitLod:
1680cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSampleProjDrefExplicitLod:
1681cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageFetch:
1682cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageGather:
1683cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageDrefGather:
1684cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageRead:
1685cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImage:
1686cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQueryFormat:
1687cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQueryOrder:
1688cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQuerySizeLod:
1689cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQuerySize:
1690cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQueryLod:
1691cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQueryLevels:
1692cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageQuerySamples:
1693cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleImplicitLod:
1694cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleExplicitLod:
1695cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleDrefImplicitLod:
1696cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleDrefExplicitLod:
1697cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleProjImplicitLod:
1698cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleProjExplicitLod:
1699cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleProjDrefImplicitLod:
1700cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseSampleProjDrefExplicitLod:
1701cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseFetch:
1702cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseGather:
1703cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageSparseDrefGather:
1704cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageTexelPointer:
1705cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            worklist.insert(insn.word(3));  // Image or sampled image
1706cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
1707cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpImageWrite:
1708cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            worklist.insert(insn.word(1));  // Image -- different operand order to above
1709cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
1710cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpFunctionCall:
1711cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            for (uint32_t i = 3; i < insn.len(); i++) {
1712cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                worklist.insert(insn.word(i));  // fn itself, and all args
1713cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            }
1714cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
17155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1716cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        case spv::OpExtInst:
1717cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            for (uint32_t i = 5; i < insn.len(); i++) {
1718cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                worklist.insert(insn.word(i));  // Operands to ext inst
1719cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            }
1720cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            break;
17215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
17225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
1723cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
17245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
17255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
17263a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes
17273a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    return ids;
17285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
17295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1730edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_push_constant_block_against_pipeline(debug_report_data *report_data,
1731416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis                                                          std::vector<VkPushConstantRange> const *push_constant_ranges,
17325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                          shader_module const *src, spirv_inst_iter type,
17335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                          VkShaderStageFlagBits stage) {
17341b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    bool skip = false;
17355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
173625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Strip off ptrs etc
17375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    type = get_struct_type(src, type, false);
17385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(type != src->end());
17395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
174025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Validate directly off the offsets. this isn't quite correct for arrays and matrices, but is a good first step.
174125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // TODO: arrays, matrices, weird sizes
17425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto insn : *src) {
17435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
17445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (insn.word(3) == spv::DecorationOffset) {
17455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                unsigned offset = insn.word(4);
1746cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto size = 4;  // Bytes; TODO: calculate this based on the type
17475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                bool found_range = false;
1749416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis                for (auto const &range : *push_constant_ranges) {
17505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    if (range.offset <= offset && range.offset + range.size >= offset + size) {
17515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        found_range = true;
17525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        if ((range.stageFlags & stage) == 0) {
17541b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
17551b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                            __LINE__, SHADER_CHECKER_PUSH_CONSTANT_NOT_ACCESSIBLE_FROM_STAGE, "SC",
17561b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                            "Push constant range covering variable starting at "
17571b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                            "offset %u not accessible from stage %s",
17581b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                            offset, string_VkShaderStageFlagBits(stage));
17595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        }
17605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        break;
17625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
17635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
17645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (!found_range) {
17661b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
17671b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                    __LINE__, SHADER_CHECKER_PUSH_CONSTANT_OUT_OF_RANGE, "SC",
17681b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                    "Push constant range covering variable starting at "
17691b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                    "offset %u not declared in layout",
17701b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                    offset);
17715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
17725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
17735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
17745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
17755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17761b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return skip;
17775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
17785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1779edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_push_constant_usage(debug_report_data *report_data,
1780416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis                                         std::vector<VkPushConstantRange> const *push_constant_ranges, shader_module const *src,
17815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                         std::unordered_set<uint32_t> accessible_ids, VkShaderStageFlagBits stage) {
17821b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    bool skip = false;
17835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto id : accessible_ids) {
17855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto def_insn = src->get_def(id);
17865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (def_insn.opcode() == spv::OpVariable && def_insn.word(3) == spv::StorageClassPushConstant) {
17871b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= validate_push_constant_block_against_pipeline(report_data, push_constant_ranges, src,
1788416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis                                                                  src->get_def(def_insn.word(1)), stage);
17895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
17905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
17915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
17921b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return skip;
17935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
17945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1795fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis// For given pipelineLayout verify that the set_layout_node at slot.first
1796fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis//  has the requested binding at slot.second and return ptr to that binding
1797bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic VkDescriptorSetLayoutBinding const *get_descriptor_binding(PIPELINE_LAYOUT_NODE const *pipelineLayout,
1798bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                  descriptor_slot_t slot) {
1799cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!pipelineLayout) return nullptr;
18005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1801cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (slot.first >= pipelineLayout->set_layouts.size()) return nullptr;
18025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1803416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis    return pipelineLayout->set_layouts[slot.first]->GetDescriptorSetLayoutBindingPtrFromBinding(slot.second);
18045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
18055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Check object status for selected flag state
180751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool validate_status(layer_data *dev_data, GLOBAL_CB_NODE *pNode, CBStatusFlags status_mask, VkFlags msg_flags,
18084f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                            const char *fail_msg, UNIQUE_VALIDATION_ERROR_CODE const msg_code) {
18093d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    if (!(pNode->status & status_mask)) {
18104f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes        char const *const message = validation_error_map[msg_code];
181151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        return log_msg(dev_data->report_data, msg_flags, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
18129b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       HandleToUint64(pNode->commandBuffer), __LINE__, msg_code, "DS", "command buffer object 0x%p: %s. %s.",
18139b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       pNode->commandBuffer, fail_msg, message);
18145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
1815e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    return false;
18165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
18175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Retrieve pipeline node ptr for given pipeline object
181951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic PIPELINE_STATE *getPipelineState(layer_data const *dev_data, VkPipeline pipeline) {
182051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->pipelineMap.find(pipeline);
182151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->pipelineMap.end()) {
1822ea8349eeee76ae2859c10870fd8bd9e60309eb28Chris Forbes        return nullptr;
18235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
1824ea8349eeee76ae2859c10870fd8bd9e60309eb28Chris Forbes    return it->second;
18255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
18265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18279a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisRENDER_PASS_STATE *GetRenderPassState(layer_data const *dev_data, VkRenderPass renderpass) {
182851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->renderPassMap.find(renderpass);
182951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->renderPassMap.end()) {
183016387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes        return nullptr;
183116387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes    }
1832fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    return it->second.get();
183316387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes}
183416387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes
18359a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisFRAMEBUFFER_STATE *GetFramebufferState(const layer_data *dev_data, VkFramebuffer framebuffer) {
183651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->frameBufferMap.find(framebuffer);
183751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->frameBufferMap.end()) {
1838f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes        return nullptr;
1839f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes    }
184004861caca7eb93a5241b164e8480bb93c826902cTobin Ehlis    return it->second.get();
1841f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes}
1842f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes
18439a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehliscvdescriptorset::DescriptorSetLayout const *GetDescriptorSetLayout(layer_data const *dev_data, VkDescriptorSetLayout dsLayout) {
184451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->descriptorSetLayoutMap.find(dsLayout);
184551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->descriptorSetLayoutMap.end()) {
184611f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes        return nullptr;
184711f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes    }
1848c8bee427d7a8ed0ccec899fbf47134d582dcafbdGabríel Arthúr Pétursson    return it->second.get();
184911f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes}
185011f1fde2721c198a619e4a22fff60eef9a16fae8Chris Forbes
185151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic PIPELINE_LAYOUT_NODE const *getPipelineLayout(layer_data const *dev_data, VkPipelineLayout pipeLayout) {
185251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->pipelineLayoutMap.find(pipeLayout);
185351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->pipelineLayoutMap.end()) {
18544a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes        return nullptr;
18554a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes    }
18564a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes    return &it->second;
18574a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes}
18584a45a42023b281f55953222c1a6c3e80f50e5f2aChris Forbes
1859e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves// Return true if for a given PSO, the given state enum is dynamic, else return false
18604c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic bool isDynamic(const PIPELINE_STATE *pPipeline, const VkDynamicState state) {
18615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pPipeline && pPipeline->graphicsPipelineCI.pDynamicState) {
18625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < pPipeline->graphicsPipelineCI.pDynamicState->dynamicStateCount; i++) {
1863cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (state == pPipeline->graphicsPipelineCI.pDynamicState->pDynamicStates[i]) return true;
18645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
18655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
1866e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    return false;
18675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
18685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
18695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Validate state stored as flags at time of draw call
18704f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayesstatic bool validate_draw_state_flags(layer_data *dev_data, GLOBAL_CB_NODE *pCB, const PIPELINE_STATE *pPipe, bool indexed,
18714f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                      UNIQUE_VALIDATION_ERROR_CODE const msg_code) {
18729c4006684a13db43f0dbc8d0015a9ef34872ca09Chris Forbes    bool result = false;
1873ca546210846c65808717f8875deae39bd227c240Tobin Ehlis    if (pPipe->graphicsPipelineCI.pInputAssemblyState &&
1874ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        ((pPipe->graphicsPipelineCI.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST) ||
1875ca546210846c65808717f8875deae39bd227c240Tobin Ehlis         (pPipe->graphicsPipelineCI.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP))) {
18763d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_LINE_WIDTH_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
18774f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic line width state not set for this command buffer", msg_code);
18783d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
187945824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves    if (pPipe->graphicsPipelineCI.pRasterizationState &&
188045824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves        (pPipe->graphicsPipelineCI.pRasterizationState->depthBiasEnable == VK_TRUE)) {
18813d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_DEPTH_BIAS_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
18824f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic depth bias state not set for this command buffer", msg_code);
18833d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
18843d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    if (pPipe->blendConstantsEnabled) {
18853d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_BLEND_CONSTANTS_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
18864f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic blend constants state not set for this command buffer", msg_code);
18873d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
188845824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves    if (pPipe->graphicsPipelineCI.pDepthStencilState &&
188945824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves        (pPipe->graphicsPipelineCI.pDepthStencilState->depthBoundsTestEnable == VK_TRUE)) {
18903d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_DEPTH_BOUNDS_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
18914f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic depth bounds state not set for this command buffer", msg_code);
18923d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
189345824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves    if (pPipe->graphicsPipelineCI.pDepthStencilState &&
189445824955f3d4d2baee6d225f84ac9c2553981b3eDustin Graves        (pPipe->graphicsPipelineCI.pDepthStencilState->stencilTestEnable == VK_TRUE)) {
18953d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_STENCIL_READ_MASK_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
18964f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic stencil read mask state not set for this command buffer", msg_code);
18973d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_STENCIL_WRITE_MASK_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
18984f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic stencil write mask state not set for this command buffer", msg_code);
18993d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_STENCIL_REFERENCE_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
19004f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Dynamic stencil reference state not set for this command buffer", msg_code);
19013d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
19021c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    if (indexed) {
19033d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        result |= validate_status(dev_data, pCB, CBSTATUS_INDEX_BUFFER_BOUND, VK_DEBUG_REPORT_ERROR_BIT_EXT,
19044f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                                  "Index buffer object not bound to this command buffer when Indexed Draw attempted", msg_code);
19053d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
19064f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes
19075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
19085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
19095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
19105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Verify attachment reference compatibility according to spec
19115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  If one array is larger, treat missing elements of shorter array as VK_ATTACHMENT_UNUSED & other array much match this
19125ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski//  If both AttachmentReference arrays have requested index, check their corresponding AttachmentDescriptions
19135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//   to make sure that format and samples counts match.
19145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  If not, they are not compatible.
19155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic bool attachment_references_compatible(const uint32_t index, const VkAttachmentReference *pPrimary,
19165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                             const uint32_t primaryCount, const VkAttachmentDescription *pPrimaryAttachments,
19175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                             const VkAttachmentReference *pSecondary, const uint32_t secondaryCount,
19185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                             const VkAttachmentDescription *pSecondaryAttachments) {
1919e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis    // Check potential NULL cases first to avoid nullptr issues later
1920e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis    if (pPrimary == nullptr) {
1921e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis        if (pSecondary == nullptr) {
1922e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis            return true;
1923e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis        }
1924e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis        return false;
1925e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis    } else if (pSecondary == nullptr) {
1926e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis        return false;
1927e62f2e46eeffde494c0d734964b389c09dec9d64Tobin Ehlis    }
1928cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (index >= primaryCount) {  // Check secondary as if primary is VK_ATTACHMENT_UNUSED
1929cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (VK_ATTACHMENT_UNUSED == pSecondary[index].attachment) return true;
1930cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    } else if (index >= secondaryCount) {  // Check primary as if secondary is VK_ATTACHMENT_UNUSED
1931cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (VK_ATTACHMENT_UNUSED == pPrimary[index].attachment) return true;
1932cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    } else {  // Format and sample count must match
19335ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski        if ((pPrimary[index].attachment == VK_ATTACHMENT_UNUSED) && (pSecondary[index].attachment == VK_ATTACHMENT_UNUSED)) {
19345ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski            return true;
19355ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski        } else if ((pPrimary[index].attachment == VK_ATTACHMENT_UNUSED) || (pSecondary[index].attachment == VK_ATTACHMENT_UNUSED)) {
19365ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski            return false;
19375ca3c071afc98f9144f489b74aa3affaa93633b0Mark Lobodzinski        }
19385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if ((pPrimaryAttachments[pPrimary[index].attachment].format ==
19395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis             pSecondaryAttachments[pSecondary[index].attachment].format) &&
19405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            (pPrimaryAttachments[pPrimary[index].attachment].samples ==
19415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis             pSecondaryAttachments[pSecondary[index].attachment].samples))
19425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            return true;
19435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
19445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Format and sample counts didn't match
19455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return false;
19465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
1947a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis// TODO : Scrub verify_renderpass_compatibility() and validateRenderPassCompatibility() and unify them and/or share code
1948266231a5421564c314f6b5d5bd3fed26fd389484Chris Forbes// For given primary RenderPass object and secondary RenderPassCreateInfo, verify that they're compatible
194951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool verify_renderpass_compatibility(const layer_data *dev_data, const VkRenderPassCreateInfo *primaryRPCI,
19508da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis                                            const VkRenderPassCreateInfo *secondaryRPCI, string &errorMsg) {
19515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (primaryRPCI->subpassCount != secondaryRPCI->subpassCount) {
1952c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes        stringstream errorStr;
19535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        errorStr << "RenderPass for primary cmdBuffer has " << primaryRPCI->subpassCount
19545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                 << " subpasses but renderPass for secondary cmdBuffer has " << secondaryRPCI->subpassCount << " subpasses.";
19555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        errorMsg = errorStr.str();
19565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return false;
19575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
19585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t spIndex = 0;
19595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (spIndex = 0; spIndex < primaryRPCI->subpassCount; ++spIndex) {
19605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // For each subpass, verify that corresponding color, input, resolve & depth/stencil attachment references are compatible
19615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primaryColorCount = primaryRPCI->pSubpasses[spIndex].colorAttachmentCount;
19625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t secondaryColorCount = secondaryRPCI->pSubpasses[spIndex].colorAttachmentCount;
19635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t colorMax = std::max(primaryColorCount, secondaryColorCount);
19645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t cIdx = 0; cIdx < colorMax; ++cIdx) {
19655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!attachment_references_compatible(cIdx, primaryRPCI->pSubpasses[spIndex].pColorAttachments, primaryColorCount,
19665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                  primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pColorAttachments,
19675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                  secondaryColorCount, secondaryRPCI->pAttachments)) {
1968c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes                stringstream errorStr;
19695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorStr << "color attachments at index " << cIdx << " of subpass index " << spIndex << " are not compatible.";
19705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorMsg = errorStr.str();
19715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return false;
19725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else if (!attachment_references_compatible(cIdx, primaryRPCI->pSubpasses[spIndex].pResolveAttachments,
19735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                         primaryColorCount, primaryRPCI->pAttachments,
19745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                         secondaryRPCI->pSubpasses[spIndex].pResolveAttachments,
19755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                         secondaryColorCount, secondaryRPCI->pAttachments)) {
1976c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes                stringstream errorStr;
19775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorStr << "resolve attachments at index " << cIdx << " of subpass index " << spIndex << " are not compatible.";
19785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorMsg = errorStr.str();
19795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return false;
19805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
19815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
1982fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes
1983bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        if (!attachment_references_compatible(0, primaryRPCI->pSubpasses[spIndex].pDepthStencilAttachment, 1,
1984bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pDepthStencilAttachment,
1985fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes                                              1, secondaryRPCI->pAttachments)) {
1986c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes            stringstream errorStr;
1987fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes            errorStr << "depth/stencil attachments of subpass index " << spIndex << " are not compatible.";
1988fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes            errorMsg = errorStr.str();
1989fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes            return false;
1990fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes        }
1991fd50683af1a7a54c6b8c13d790ad57c48072f55bChris Forbes
19925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primaryInputCount = primaryRPCI->pSubpasses[spIndex].inputAttachmentCount;
19935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t secondaryInputCount = secondaryRPCI->pSubpasses[spIndex].inputAttachmentCount;
19945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t inputMax = std::max(primaryInputCount, secondaryInputCount);
19955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < inputMax; ++i) {
19961e49a9dd0518c3cd335dd040218aa9c25d7cb600Tobin Ehlis            if (!attachment_references_compatible(i, primaryRPCI->pSubpasses[spIndex].pInputAttachments, primaryInputCount,
19975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                                  primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pInputAttachments,
19981e49a9dd0518c3cd335dd040218aa9c25d7cb600Tobin Ehlis                                                  secondaryInputCount, secondaryRPCI->pAttachments)) {
1999c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes                stringstream errorStr;
20005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorStr << "input attachments at index " << i << " of subpass index " << spIndex << " are not compatible.";
20015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                errorMsg = errorStr.str();
20025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return false;
20035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
20045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
20055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
20065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return true;
20075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
20085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2009397d27da37095073c8b86f9ff5289d0a39ce486eTobin Ehlis// For given cvdescriptorset::DescriptorSet, verify that its Set is compatible w/ the setLayout corresponding to
2010397d27da37095073c8b86f9ff5289d0a39ce486eTobin Ehlis// pipelineLayout[layoutIndex]
201112b7fc342b53fbdd399aae4a85959e37685936acChris Forbesstatic bool verify_set_layout_compatibility(const cvdescriptorset::DescriptorSet *descriptor_set,
201269b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                                            PIPELINE_LAYOUT_NODE const *pipeline_layout, const uint32_t layoutIndex,
201369b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                                            string &errorMsg) {
2014416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis    auto num_sets = pipeline_layout->set_layouts.size();
20159b5d124aff50234cb0450e1b805baef577c90d83Tobin Ehlis    if (layoutIndex >= num_sets) {
2016c07fa78efa7d4edfaa4ffbb0c2046ee8154b27beChris Forbes        stringstream errorStr;
201769b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis        errorStr << "VkPipelineLayout (" << pipeline_layout->layout << ") only contains " << num_sets
201869b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                 << " setLayouts corresponding to sets 0-" << num_sets - 1 << ", but you're attempting to bind set to index "
201969b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                 << layoutIndex;
20205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        errorMsg = errorStr.str();
20215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return false;
20225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2023416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis    auto layout_node = pipeline_layout->set_layouts[layoutIndex];
20241c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    return descriptor_set->IsCompatible(layout_node, &errorMsg);
20255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
20265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Validate that data for each specialization entry is fully contained within the buffer.
2028edef66e03ed509994449d598f4fadea1a487d41bChris Forbesstatic bool validate_specialization_offsets(debug_report_data *report_data, VkPipelineShaderStageCreateInfo const *info) {
20291b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    bool skip = false;
20305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkSpecializationInfo const *spec = info->pSpecializationInfo;
20325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (spec) {
20345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto i = 0u; i < spec->mapEntryCount; i++) {
2035315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            // TODO: This is a good place for VALIDATION_ERROR_1360060a.
20365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (spec->pMapEntries[i].offset + spec->pMapEntries[i].size > spec->dataSize) {
20371b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
2038315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                VALIDATION_ERROR_1360060c, "SC",
20391b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                "Specialization entry %u (for constant id %u) references memory outside provided "
20401b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                "specialization data (bytes %u.." PRINTF_SIZE_T_SPECIFIER "; " PRINTF_SIZE_T_SPECIFIER
20411b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                " bytes provided). %s.",
20421b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                i, spec->pMapEntries[i].constantID, spec->pMapEntries[i].offset,
20431b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                spec->pMapEntries[i].offset + spec->pMapEntries[i].size - 1, spec->dataSize,
2044315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                validation_error_map[VALIDATION_ERROR_1360060c]);
20455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
20465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
20475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
20485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20491b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return skip;
20505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
20515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2052bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool descriptor_type_match(shader_module const *module, uint32_t type_id, VkDescriptorType descriptor_type,
2053bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                  unsigned &descriptor_count) {
20545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    auto type = module->get_def(type_id);
20555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20561b8c581791ac3c05d7829e04a2d8ecb964b8f2a6Chris Forbes    descriptor_count = 1;
20571b8c581791ac3c05d7829e04a2d8ecb964b8f2a6Chris Forbes
205825002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Strip off any array or ptrs. Where we remove array levels, adjust the  descriptor count for each dimension.
20595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while (type.opcode() == spv::OpTypeArray || type.opcode() == spv::OpTypePointer) {
20607b892d2fc502b57d26dc9bff61b0f23cccc595fdChris Forbes        if (type.opcode() == spv::OpTypeArray) {
20617b892d2fc502b57d26dc9bff61b0f23cccc595fdChris Forbes            descriptor_count *= get_constant_value(module, type.word(3));
20627b892d2fc502b57d26dc9bff61b0f23cccc595fdChris Forbes            type = module->get_def(type.word(2));
2063bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        } else {
20647b892d2fc502b57d26dc9bff61b0f23cccc595fdChris Forbes            type = module->get_def(type.word(3));
20657b892d2fc502b57d26dc9bff61b0f23cccc595fdChris Forbes        }
20665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
20675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
20685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    switch (type.opcode()) {
2069cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeStruct: {
2070cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            for (auto insn : *module) {
2071cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (insn.opcode() == spv::OpDecorate && insn.word(1) == type.word(1)) {
2072cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    if (insn.word(2) == spv::DecorationBlock) {
2073cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ||
2074cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                               descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
2075cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    } else if (insn.word(2) == spv::DecorationBufferBlock) {
2076cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ||
2077cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                               descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
2078cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    }
20795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
20805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
20815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2082cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Invalid
2083cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return false;
2084cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
20855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2086cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeSampler:
2087cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return descriptor_type == VK_DESCRIPTOR_TYPE_SAMPLER || descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
20885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2089cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeSampledImage:
2090cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) {
2091cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // Slight relaxation for some GLSL historical madness: samplerBuffer doesn't really have a sampler, and a texel
2092cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // buffer descriptor doesn't really provide one. Allow this slight mismatch.
2093cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto image_type = module->get_def(type.word(2));
2094cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto dim = image_type.word(3);
2095cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto sampled = image_type.word(7);
2096cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return dim == spv::DimBuffer && sampled == 1;
2097cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
2098cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
20995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2100cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        case spv::OpTypeImage: {
2101cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // Many descriptor types backing image types-- depends on dimension and whether the image will be used with a sampler.
2102cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // SPIRV for Vulkan requires that sampled be 1 or 2 -- leaving the decision to runtime is unacceptable.
2103cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            auto dim = type.word(3);
2104cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            auto sampled = type.word(7);
21055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2106cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (dim == spv::DimSubpassData) {
2107cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return descriptor_type == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
2108cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else if (dim == spv::DimBuffer) {
2109cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (sampled == 1) {
2110cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    return descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
2111cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                } else {
2112cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
2113cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
2114cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else if (sampled == 1) {
2115cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return descriptor_type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ||
2116cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                       descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
21175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else {
2118cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
21195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
21205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
21215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2122cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        // We shouldn't really see any other junk types -- but if we do, they're a mismatch.
2123cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
2124cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            return false;  // Mismatch
21255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
21265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
21275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
21284110a6be7a8a287d459475926985f71c27d01298Chris Forbesstatic bool require_feature(debug_report_data *report_data, VkBool32 feature, char const *feature_name) {
2129a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    if (!feature) {
21305b9ab1fb8720c30edfbe8dd974e2364425471ad5Mark Lobodzinski        if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
2131cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    SHADER_CHECKER_FEATURE_NOT_ENABLED, "SC",
2132cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "Shader requires VkPhysicalDeviceFeatures::%s but is not "
2133cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "enabled on the device",
2134a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes                    feature_name)) {
21351b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            return true;
2136a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes        }
2137a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    }
2138a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
21391b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return false;
2140a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes}
2141a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
214259e12b842592a05706886ab852b767ba251d9467Chris Forbesstatic bool require_extension(debug_report_data *report_data, bool extension, char const *extension_name) {
21437b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes    if (!extension) {
21445b9ab1fb8720c30edfbe8dd974e2364425471ad5Mark Lobodzinski        if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
21457b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes                    SHADER_CHECKER_FEATURE_NOT_ENABLED, "SC",
21467b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes                    "Shader requires extension %s but is not "
21477b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes                    "enabled on the device",
21487b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes                    extension_name)) {
21491b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            return true;
21507b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes        }
21517b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes    }
21527b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes
21531b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return false;
21547b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes}
21557b6006f355aaacf7fc7f0d575b40285b89ecd279Chris Forbes
2156ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbesstatic bool validate_shader_capabilities(layer_data *dev_data, shader_module const *src) {
21571b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    bool skip = false;
2158a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2159ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes    auto report_data = dev_data->report_data;
2160ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes    auto const & enabledFeatures = dev_data->enabled_features;
2161ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes
2162a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes    struct CapabilityInfo {
2163a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        char const *name;
2164a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        VkBool32 const VkPhysicalDeviceFeatures::*feature;
2165bdaffa5403b494e78a9b461182e2e6360c2b775cChris Forbes        bool const DeviceExtensions::*extension;
2166a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes    };
2167a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes
2168a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes    using F = VkPhysicalDeviceFeatures;
2169bdaffa5403b494e78a9b461182e2e6360c2b775cChris Forbes    using E = DeviceExtensions;
2170a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes
2171a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes    // clang-format off
2172a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes    static const std::unordered_map<uint32_t, CapabilityInfo> capabilities = {
2173a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        // Capabilities always supported by a Vulkan 1.0 implementation -- no
2174a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        // feature bits.
2175a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityMatrix, {nullptr}},
2176a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityShader, {nullptr}},
2177a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityInputAttachment, {nullptr}},
2178a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilitySampled1D, {nullptr}},
2179a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityImage1D, {nullptr}},
2180a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilitySampledBuffer, {nullptr}},
2181a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityImageQuery, {nullptr}},
2182a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityDerivativeControl, {nullptr}},
2183a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes
2184a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        // Capabilities that are optionally supported, but require a feature to
2185a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        // be enabled on the device
2186a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityGeometry, {"geometryShader", &F::geometryShader}},
2187a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityTessellation, {"tessellationShader", &F::tessellationShader}},
2188a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityFloat64, {"shaderFloat64", &F::shaderFloat64}},
2189a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityInt64, {"shaderInt64", &F::shaderInt64}},
2190a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityTessellationPointSize, {"shaderTessellationAndGeometryPointSize", &F::shaderTessellationAndGeometryPointSize}},
2191a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityGeometryPointSize, {"shaderTessellationAndGeometryPointSize", &F::shaderTessellationAndGeometryPointSize}},
2192a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityImageGatherExtended, {"shaderImageGatherExtended", &F::shaderImageGatherExtended}},
2193a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityStorageImageMultisample, {"shaderStorageImageMultisample", &F::shaderStorageImageMultisample}},
2194a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityUniformBufferArrayDynamicIndexing, {"shaderUniformBufferArrayDynamicIndexing", &F::shaderUniformBufferArrayDynamicIndexing}},
2195a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilitySampledImageArrayDynamicIndexing, {"shaderSampledImageArrayDynamicIndexing", &F::shaderSampledImageArrayDynamicIndexing}},
2196a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityStorageBufferArrayDynamicIndexing, {"shaderStorageBufferArrayDynamicIndexing", &F::shaderStorageBufferArrayDynamicIndexing}},
2197a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityStorageImageArrayDynamicIndexing, {"shaderStorageImageArrayDynamicIndexing", &F::shaderStorageBufferArrayDynamicIndexing}},
2198a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityClipDistance, {"shaderClipDistance", &F::shaderClipDistance}},
2199a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityCullDistance, {"shaderCullDistance", &F::shaderCullDistance}},
2200a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityImageCubeArray, {"imageCubeArray", &F::imageCubeArray}},
2201a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilitySampleRateShading, {"sampleRateShading", &F::sampleRateShading}},
2202a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilitySparseResidency, {"shaderResourceResidency", &F::shaderResourceResidency}},
2203a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityMinLod, {"shaderResourceMinLod", &F::shaderResourceMinLod}},
2204a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilitySampledCubeArray, {"imageCubeArray", &F::imageCubeArray}},
2205a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityImageMSArray, {"shaderStorageImageMultisample", &F::shaderStorageImageMultisample}},
2206a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityStorageImageExtendedFormats, {"shaderStorageImageExtendedFormats", &F::shaderStorageImageExtendedFormats}},
2207a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityInterpolationFunction, {"sampleRateShading", &F::sampleRateShading}},
2208a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityStorageImageReadWithoutFormat, {"shaderStorageImageReadWithoutFormat", &F::shaderStorageImageReadWithoutFormat}},
2209a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityStorageImageWriteWithoutFormat, {"shaderStorageImageWriteWithoutFormat", &F::shaderStorageImageWriteWithoutFormat}},
2210a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        {spv::CapabilityMultiViewport, {"multiViewport", &F::multiViewport}},
2211a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes
2212a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes        // Capabilities that require an extension
2213d4eaca34eca7f4b4e34190c441a579347bb2016aMark Lobodzinski        {spv::CapabilityDrawParameters, {VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME, nullptr, &E::vk_khr_shader_draw_parameters}},
2214d4eaca34eca7f4b4e34190c441a579347bb2016aMark Lobodzinski        {spv::CapabilityGeometryShaderPassthroughNV, {VK_NV_GEOMETRY_SHADER_PASSTHROUGH_EXTENSION_NAME, nullptr, &E::vk_nv_geometry_shader_passthrough}},
2215d4eaca34eca7f4b4e34190c441a579347bb2016aMark Lobodzinski        {spv::CapabilitySampleMaskOverrideCoverageNV, {VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_EXTENSION_NAME, nullptr, &E::vk_nv_sample_mask_override_coverage}},
2216d4eaca34eca7f4b4e34190c441a579347bb2016aMark Lobodzinski        {spv::CapabilityShaderViewportIndexLayerNV, {VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME, nullptr, &E::vk_nv_viewport_array2}},
2217d4eaca34eca7f4b4e34190c441a579347bb2016aMark Lobodzinski        {spv::CapabilityShaderViewportMaskNV, {VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME, nullptr, &E::vk_nv_viewport_array2}},
2218d4eaca34eca7f4b4e34190c441a579347bb2016aMark Lobodzinski        {spv::CapabilitySubgroupBallotKHR, {VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME, nullptr, &E::vk_ext_shader_subgroup_ballot }},
2219d4eaca34eca7f4b4e34190c441a579347bb2016aMark Lobodzinski        {spv::CapabilitySubgroupVoteKHR, {VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME, nullptr, &E::vk_ext_shader_subgroup_vote }},
2220a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes    };
2221a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes    // clang-format on
2222a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes
2223a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    for (auto insn : *src) {
2224a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes        if (insn.opcode() == spv::OpCapability) {
2225a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes            auto it = capabilities.find(insn.word(1));
2226a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes            if (it != capabilities.end()) {
2227a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes                if (it->second.feature) {
2228a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes                    skip |= require_feature(report_data, enabledFeatures.*(it->second.feature), it->second.name);
2229a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes                }
2230a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes                if (it->second.extension) {
2231a149f1a0cb39b48b19822c8cf9ef2426cd2251dfMark Lobodzinski                    skip |= require_extension(report_data, dev_data->extensions.*(it->second.extension), it->second.name);
2232a469089d367e8221926f7048bd4dcb2dc2721c0aChris Forbes                }
2233a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes            }
2234a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes        }
2235a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes    }
2236a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
22371b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return skip;
2238a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes}
2239a3c20a28f119d24faec013fb4513605b654c36c3Chris Forbes
2240b2a61f3cd17c68887759817059fa1872f1e1464aChris Forbesstatic uint32_t descriptor_type_to_reqs(shader_module const *module, uint32_t type_id) {
22412aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes    auto type = module->get_def(type_id);
22422aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes
22432aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes    while (true) {
22442aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes        switch (type.opcode()) {
2245cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeArray:
2246cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeSampledImage:
2247cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                type = module->get_def(type.word(2));
2248cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
2249cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypePointer:
2250cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                type = module->get_def(type.word(3));
2251cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
2252cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case spv::OpTypeImage: {
2253cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto dim = type.word(3);
2254cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto arrayed = type.word(5);
2255cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                auto msaa = type.word(6);
2256cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski
2257cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                switch (dim) {
2258cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    case spv::Dim1D:
2259cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return arrayed ? DESCRIPTOR_REQ_VIEW_TYPE_1D_ARRAY : DESCRIPTOR_REQ_VIEW_TYPE_1D;
2260cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    case spv::Dim2D:
2261cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return (msaa ? DESCRIPTOR_REQ_MULTI_SAMPLE : DESCRIPTOR_REQ_SINGLE_SAMPLE) |
2262cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                               (arrayed ? DESCRIPTOR_REQ_VIEW_TYPE_2D_ARRAY : DESCRIPTOR_REQ_VIEW_TYPE_2D);
2263cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    case spv::Dim3D:
2264cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return DESCRIPTOR_REQ_VIEW_TYPE_3D;
2265cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    case spv::DimCube:
2266cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return arrayed ? DESCRIPTOR_REQ_VIEW_TYPE_CUBE_ARRAY : DESCRIPTOR_REQ_VIEW_TYPE_CUBE;
2267cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    case spv::DimSubpassData:
2268cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return msaa ? DESCRIPTOR_REQ_MULTI_SAMPLE : DESCRIPTOR_REQ_SINGLE_SAMPLE;
2269cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    default:  // buffer, etc.
2270cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        return 0;
2271cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
22722aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes            }
2273cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
2274cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                return 0;
22752aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes        }
22762aa6e0c0e34095c0c84699f98172d05750a9c587Chris Forbes    }
2277b2a61f3cd17c68887759817059fa1872f1e1464aChris Forbes}
2278b2a61f3cd17c68887759817059fa1872f1e1464aChris Forbes
2279cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskistatic bool validate_pipeline_shader_stage(
2280ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes    layer_data *dev_data, VkPipelineShaderStageCreateInfo const *pStage, PIPELINE_STATE *pipeline,
2281ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes    shader_module **out_module, spirv_inst_iter *out_entrypoint) {
22821b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    bool skip = false;
2283ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes    auto module_it = dev_data->shaderModuleMap.find(pStage->module);
228469f9a551bfb1fd5334950f9685c12c5adda23dfbChris Forbes    auto module = *out_module = module_it->second.get();
2285ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes    auto report_data = dev_data->report_data;
228678be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
22871b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    if (!module->has_valid_spirv) return false;
2288c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski
228925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Find the entrypoint
229078be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    auto entrypoint = *out_entrypoint = find_entrypoint(module, pStage->pName, pStage->stage);
229178be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    if (entrypoint == module->end()) {
22925b9ab1fb8720c30edfbe8dd974e2364425471ad5Mark Lobodzinski        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
2293315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                    VALIDATION_ERROR_10600586, "SC", "No entrypoint found named `%s` for stage %s. %s.", pStage->pName,
2294315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                    string_VkShaderStageFlagBits(pStage->stage), validation_error_map[VALIDATION_ERROR_10600586])) {
22951b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            return true;  // no point continuing beyond here, any analysis is just going to be garbage.
229678be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        }
229778be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    }
229878be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
229925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Validate shader capabilities against enabled device features
23001b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    skip |= validate_shader_capabilities(dev_data, module);
230178be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
230225002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Mark accessible ids
23033a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    auto accessible_ids = mark_accessible_ids(module, entrypoint);
230478be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
230525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Validate descriptor set layout against what the entrypoint actually uses
23063a1adf43eb19fc8e32b5cf64eab56d120d6e00e8Chris Forbes    auto descriptor_uses = collect_interface_by_descriptor_slot(report_data, module, accessible_ids);
230778be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
23082e0eca3d6fad72a29ae072e3895e29a2d2d66476Tobin Ehlis    auto pipelineLayout = pipeline->pipeline_layout;
2309ed399f66e0512ef077d0e0a7cb903248726d2424Chris Forbes
23101b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    skip |= validate_specialization_offsets(report_data, pStage);
23111b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    skip |= validate_push_constant_usage(report_data, &pipelineLayout.push_constant_ranges, module, accessible_ids, pStage->stage);
231278be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
231325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Validate descriptor use
231478be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    for (auto use : descriptor_uses) {
231578be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        // While validating shaders capture which slots are used by the pipeline
2316bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto &reqs = pipeline->active_slots[use.first.first][use.first.second];
2317b2a61f3cd17c68887759817059fa1872f1e1464aChris Forbes        reqs = descriptor_req(reqs | descriptor_type_to_reqs(module, use.second.type_id));
231878be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
231925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Verify given pipelineLayout has requested setLayout with requested binding
2320c8268861aaa8f9c47920065d6323e4609e5081b0Tobin Ehlis        const auto &binding = get_descriptor_binding(&pipelineLayout, use.first);
232178be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        unsigned required_descriptor_count;
232278be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
232378be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        if (!binding) {
23241b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
23251b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            SHADER_CHECKER_MISSING_DESCRIPTOR, "SC",
23261b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            "Shader uses descriptor slot %u.%u (used as type `%s`) but not declared in pipeline layout",
23271b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            use.first.first, use.first.second, describe_type(module, use.second.type_id).c_str());
232878be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        } else if (~binding->stageFlags & pStage->stage) {
23291b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
23301b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            SHADER_CHECKER_DESCRIPTOR_NOT_ACCESSIBLE_FROM_STAGE, "SC",
23311b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            "Shader uses descriptor slot %u.%u (used "
23321b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            "as type `%s`) but descriptor not "
23331b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            "accessible from stage %s",
23341b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            use.first.first, use.first.second, describe_type(module, use.second.type_id).c_str(),
23351b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            string_VkShaderStageFlagBits(pStage->stage));
2336bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        } else if (!descriptor_type_match(module, use.second.type_id, binding->descriptorType, required_descriptor_count)) {
23371b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
23381b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            SHADER_CHECKER_DESCRIPTOR_TYPE_MISMATCH, "SC",
23391b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            "Type mismatch on descriptor slot "
23401b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            "%u.%u (used as type `%s`) but "
23411b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            "descriptor of type %s",
23421b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            use.first.first, use.first.second, describe_type(module, use.second.type_id).c_str(),
23431b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            string_VkDescriptorType(binding->descriptorType));
234478be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        } else if (binding->descriptorCount < required_descriptor_count) {
23451b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
23461b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            SHADER_CHECKER_DESCRIPTOR_TYPE_MISMATCH, "SC",
23471b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            "Shader expects at least %u descriptors for binding %u.%u (used as type `%s`) but only %u provided",
23481b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            required_descriptor_count, use.first.first, use.first.second,
23491b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            describe_type(module, use.second.type_id).c_str(), binding->descriptorCount);
235078be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        }
235178be5018e238bd464b1f1c55138df277c0c18922Chris Forbes    }
235278be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
235325002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski    // Validate use of input attachments against subpass structure
2354c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes    if (pStage->stage == VK_SHADER_STAGE_FRAGMENT_BIT) {
235512b7fc342b53fbdd399aae4a85959e37685936acChris Forbes        auto input_attachment_uses = collect_interface_by_input_attachment_index(module, accessible_ids);
2356c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes
2357c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes        auto rpci = pipeline->render_pass_ci.ptr();
2358c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes        auto subpass = pipeline->graphicsPipelineCI.subpass;
2359c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes
2360c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes        for (auto use : input_attachment_uses) {
2361c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes            auto input_attachments = rpci->pSubpasses[subpass].pInputAttachments;
2362bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            auto index = (input_attachments && use.first < rpci->pSubpasses[subpass].inputAttachmentCount)
2363bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             ? input_attachments[use.first].attachment
2364bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                             : VK_ATTACHMENT_UNUSED;
2365c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes
2366c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes            if (index == VK_ATTACHMENT_UNUSED) {
23671b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
23681b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                SHADER_CHECKER_MISSING_INPUT_ATTACHMENT, "SC",
23691b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                                "Shader consumes input attachment index %d but not provided in subpass", use.first);
2370f0fdde7692ffd5175435cc3bf3412b8468054f38Chris Forbes            } else if (!(get_format_type(rpci->pAttachments[index].format) & get_fundamental_type(module, use.second.type_id))) {
23711b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                skip |=
23721b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                    log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
2373eeb9f6a27f1acc11e54080fb3bcda7b513b5c89fChris Forbes                            SHADER_CHECKER_INPUT_ATTACHMENT_TYPE_MISMATCH, "SC",
2374bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "Subpass input attachment %u format of %s does not match type used in shader `%s`", use.first,
23751b52022446fb65466dfcee491393670ac12aaa33Chris Forbes                            string_VkFormat(rpci->pAttachments[index].format), describe_type(module, use.second.type_id).c_str());
2376eeb9f6a27f1acc11e54080fb3bcda7b513b5c89fChris Forbes            }
2377c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes        }
2378c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes    }
2379c024994b70f304ed7c6a472b90803c9911be09ddChris Forbes
23801b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return skip;
238178be5018e238bd464b1f1c55138df277c0c18922Chris Forbes}
238278be5018e238bd464b1f1c55138df277c0c18922Chris Forbes
2383a61b537fcb6a4f7b92cd217b3964ad7a48109da1Tobin Ehlis// Validate that the shaders used by the given pipeline and store the active_slots
2384a61b537fcb6a4f7b92cd217b3964ad7a48109da1Tobin Ehlis//  that are actually used by the pipeline into pPipeline->active_slots
2385ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbesstatic bool validate_and_capture_pipeline_shader_state(layer_data *dev_data, PIPELINE_STATE *pPipeline) {
23866660d6f3e4e4c895063e8d99098162bd2f508b24Chris Forbes    auto pCreateInfo = pPipeline->graphicsPipelineCI.ptr();
23875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    int vertex_stage = get_shader_stage_id(VK_SHADER_STAGE_VERTEX_BIT);
23885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    int fragment_stage = get_shader_stage_id(VK_SHADER_STAGE_FRAGMENT_BIT);
23895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
23905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    shader_module *shaders[5];
23915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    memset(shaders, 0, sizeof(shaders));
23925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    spirv_inst_iter entrypoints[5];
23935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    memset(entrypoints, 0, sizeof(entrypoints));
23941b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    bool skip = false;
23955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
23965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) {
23976660d6f3e4e4c895063e8d99098162bd2f508b24Chris Forbes        auto pStage = &pCreateInfo->pStages[i];
239878be5018e238bd464b1f1c55138df277c0c18922Chris Forbes        auto stage_id = get_shader_stage_id(pStage->stage);
23991b52022446fb65466dfcee491393670ac12aaa33Chris Forbes        skip |= validate_pipeline_shader_stage(dev_data, pStage, pPipeline, &shaders[stage_id], &entrypoints[stage_id]);
24005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
24015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2402d5365427feb4a6c16371ecb651afa37b89dabd96Chris Forbes    // if the shader stages are no good individually, cross-stage validation is pointless.
24031b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    if (skip) return true;
2404b7476f4c4998ae20e579bd2d134667b71acdbf91Chris Forbes
2405ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes    auto vi = pCreateInfo->pVertexInputState;
24065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
24075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (vi) {
24081b52022446fb65466dfcee491393670ac12aaa33Chris Forbes        skip |= validate_vi_consistency(dev_data->report_data, vi);
24095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
24105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2411c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski    if (shaders[vertex_stage] && shaders[vertex_stage]->has_valid_spirv) {
24121b52022446fb65466dfcee491393670ac12aaa33Chris Forbes        skip |= validate_vi_against_vs_inputs(dev_data->report_data, vi, shaders[vertex_stage], entrypoints[vertex_stage]);
24135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
24145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
24155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    int producer = get_shader_stage_id(VK_SHADER_STAGE_VERTEX_BIT);
24165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    int consumer = get_shader_stage_id(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
24175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
24185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    while (!shaders[producer] && producer != fragment_stage) {
24195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        producer++;
24205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        consumer++;
24215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
24225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
24235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (; producer != fragment_stage && consumer <= fragment_stage; consumer++) {
24245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        assert(shaders[producer]);
2425c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski        if (shaders[consumer] && shaders[consumer]->has_valid_spirv && shaders[producer]->has_valid_spirv) {
24261b52022446fb65466dfcee491393670ac12aaa33Chris Forbes            skip |= validate_interface_between_stages(dev_data->report_data, shaders[producer], entrypoints[producer],
2427bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      &shader_stage_attribs[producer], shaders[consumer], entrypoints[consumer],
2428bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      &shader_stage_attribs[consumer]);
24295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
24305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            producer = consumer;
24315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
24325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
24335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2434c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski    if (shaders[fragment_stage] && shaders[fragment_stage]->has_valid_spirv) {
24351b52022446fb65466dfcee491393670ac12aaa33Chris Forbes        skip |= validate_fs_outputs_against_render_pass(dev_data->report_data, shaders[fragment_stage], entrypoints[fragment_stage],
24368da1edac0fbed13831b2f458f27c51e64d6210ffTobin Ehlis                                                        pPipeline->render_pass_ci.ptr(), pCreateInfo->subpass);
24375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
24385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
24391b52022446fb65466dfcee491393670ac12aaa33Chris Forbes    return skip;
24405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
24415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2442ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbesstatic bool validate_compute_pipeline(layer_data *dev_data, PIPELINE_STATE *pPipeline) {
24436660d6f3e4e4c895063e8d99098162bd2f508b24Chris Forbes    auto pCreateInfo = pPipeline->computePipelineCI.ptr();
244403857e826cdc6e8d814137fb3245596ca1cb7bc7Chris Forbes
244503857e826cdc6e8d814137fb3245596ca1cb7bc7Chris Forbes    shader_module *module;
244603857e826cdc6e8d814137fb3245596ca1cb7bc7Chris Forbes    spirv_inst_iter entrypoint;
244703857e826cdc6e8d814137fb3245596ca1cb7bc7Chris Forbes
2448ecdfecfe60f239f0d66bc398b9172ef72497597aChris Forbes    return validate_pipeline_shader_stage(dev_data, &pCreateInfo->stage, pPipeline, &module, &entrypoint);
244903857e826cdc6e8d814137fb3245596ca1cb7bc7Chris Forbes}
24505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Return Set node ptr for specified set or else NULL
24519a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehliscvdescriptorset::DescriptorSet *GetSetNode(const layer_data *dev_data, VkDescriptorSet set) {
245251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto set_it = dev_data->setMap.find(set);
245351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (set_it == dev_data->setMap.end()) {
24545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return NULL;
24555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2456104ab082916e41467ef60baaab7a5a8b2e02c59cTobin Ehlis    return set_it->second;
24575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
24585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2459eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young// For given pipeline, return number of MSAA samples, or one if MSAA disabled
24604c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic VkSampleCountFlagBits getNumSamples(PIPELINE_STATE const *pipe) {
2461ea8349eeee76ae2859c10870fd8bd9e60309eb28Chris Forbes    if (pipe->graphicsPipelineCI.pMultisampleState != NULL &&
2462ea8349eeee76ae2859c10870fd8bd9e60309eb28Chris Forbes        VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO == pipe->graphicsPipelineCI.pMultisampleState->sType) {
2463eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young        return pipe->graphicsPipelineCI.pMultisampleState->rasterizationSamples;
2464eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    }
2465eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    return VK_SAMPLE_COUNT_1_BIT;
2466eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young}
2467eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
2468bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic void list_bits(std::ostream &s, uint32_t bits) {
2469b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes    for (int i = 0; i < 32 && bits; i++) {
2470b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes        if (bits & (1 << i)) {
2471b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            s << i;
2472b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            bits &= ~(1 << i);
2473b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            if (bits) {
2474b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                s << ",";
2475b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            }
2476b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes        }
2477b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes    }
2478b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes}
2479b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes
2480eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young// Validate draw-time state related to the PSO
248151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool ValidatePipelineDrawtimeState(layer_data const *dev_data, LAST_BOUND_STATE const &state, const GLOBAL_CB_NODE *pCB,
24824c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis                                          PIPELINE_STATE const *pPipeline) {
24833251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
248429d196e071b2dc1db47702085469396f2b956820Chris Forbes
2485d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen    // Verify vertex binding
248629d196e071b2dc1db47702085469396f2b956820Chris Forbes    if (pPipeline->vertexBindingDescriptions.size() > 0) {
248729d196e071b2dc1db47702085469396f2b956820Chris Forbes        for (size_t i = 0; i < pPipeline->vertexBindingDescriptions.size(); i++) {
2488312129ec52e6249aa453e27e6be17a8dab1e98b8Tobin Ehlis            auto vertex_binding = pPipeline->vertexBindingDescriptions[i].binding;
2489312129ec52e6249aa453e27e6be17a8dab1e98b8Tobin Ehlis            if ((pCB->currentDrawData.buffers.size() < (vertex_binding + 1)) ||
2490312129ec52e6249aa453e27e6be17a8dab1e98b8Tobin Ehlis                (pCB->currentDrawData.buffers[vertex_binding] == VK_NULL_HANDLE)) {
24913251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
2492df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
24939b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pCB->commandBuffer), __LINE__, DRAWSTATE_VTX_INDEX_OUT_OF_BOUNDS, "DS",
2494cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "The Pipeline State Object (0x%" PRIxLEAST64
2495cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            ") expects that this Command Buffer's vertex binding Index %u "
2496cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "should be set via vkCmdBindVertexBuffers. This is because VkVertexInputBindingDescription struct "
2497cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "at index " PRINTF_SIZE_T_SPECIFIER " of pVertexBindingDescriptions has a binding value of %u.",
24989b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(state.pipeline_state->pipeline), vertex_binding, i, vertex_binding);
249929d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
250029d196e071b2dc1db47702085469396f2b956820Chris Forbes        }
250129d196e071b2dc1db47702085469396f2b956820Chris Forbes    } else {
250258b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis        if (!pCB->currentDrawData.buffers.empty() && !pCB->vertex_buffer_used) {
25033251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
25049b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(pCB->commandBuffer), __LINE__,
25059b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            DRAWSTATE_VTX_INDEX_OUT_OF_BOUNDS, "DS",
25063251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Vertex buffers are bound to command buffer (0x%p"
25073251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            ") but no vertex buffers are attached to this Pipeline State Object (0x%" PRIxLEAST64 ").",
25089b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            pCB->commandBuffer, HandleToUint64(state.pipeline_state->pipeline));
250929d196e071b2dc1db47702085469396f2b956820Chris Forbes        }
251029d196e071b2dc1db47702085469396f2b956820Chris Forbes    }
251129d196e071b2dc1db47702085469396f2b956820Chris Forbes    // If Viewport or scissors are dynamic, verify that dynamic count matches PSO count.
251229d196e071b2dc1db47702085469396f2b956820Chris Forbes    // Skip check if rasterization is disabled or there is no viewport.
251329d196e071b2dc1db47702085469396f2b956820Chris Forbes    if ((!pPipeline->graphicsPipelineCI.pRasterizationState ||
251429d196e071b2dc1db47702085469396f2b956820Chris Forbes         (pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable == VK_FALSE)) &&
251529d196e071b2dc1db47702085469396f2b956820Chris Forbes        pPipeline->graphicsPipelineCI.pViewportState) {
251629d196e071b2dc1db47702085469396f2b956820Chris Forbes        bool dynViewport = isDynamic(pPipeline, VK_DYNAMIC_STATE_VIEWPORT);
251729d196e071b2dc1db47702085469396f2b956820Chris Forbes        bool dynScissor = isDynamic(pPipeline, VK_DYNAMIC_STATE_SCISSOR);
2518b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes
251929d196e071b2dc1db47702085469396f2b956820Chris Forbes        if (dynViewport) {
2520b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            auto requiredViewportsMask = (1 << pPipeline->graphicsPipelineCI.pViewportState->viewportCount) - 1;
2521b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            auto missingViewportMask = ~pCB->viewportMask & requiredViewportsMask;
2522b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            if (missingViewportMask) {
2523b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                std::stringstream ss;
2524b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                ss << "Dynamic viewport(s) ";
2525b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                list_bits(ss, missingViewportMask);
2526d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen                ss << " are used by pipeline state object, but were not provided via calls to vkCmdSetViewport().";
25273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
25283251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", "%s", ss.str().c_str());
252929d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
253029d196e071b2dc1db47702085469396f2b956820Chris Forbes        }
2531b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes
253229d196e071b2dc1db47702085469396f2b956820Chris Forbes        if (dynScissor) {
2533b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            auto requiredScissorMask = (1 << pPipeline->graphicsPipelineCI.pViewportState->scissorCount) - 1;
2534b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            auto missingScissorMask = ~pCB->scissorMask & requiredScissorMask;
2535b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes            if (missingScissorMask) {
2536b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                std::stringstream ss;
2537b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                ss << "Dynamic scissor(s) ";
2538b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes                list_bits(ss, missingScissorMask);
2539d79335137b414d5f89284a9ab3e014beb4ada3ebMike Weiblen                ss << " are used by pipeline state object, but were not provided via calls to vkCmdSetScissor().";
25403251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
25413251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", "%s", ss.str().c_str());
254229d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
254329d196e071b2dc1db47702085469396f2b956820Chris Forbes        }
254429d196e071b2dc1db47702085469396f2b956820Chris Forbes    }
254529d196e071b2dc1db47702085469396f2b956820Chris Forbes
254629d196e071b2dc1db47702085469396f2b956820Chris Forbes    // Verify that any MSAA request in PSO matches sample# in bound FB
254729d196e071b2dc1db47702085469396f2b956820Chris Forbes    // Skip the check if rasterization is disabled.
254829d196e071b2dc1db47702085469396f2b956820Chris Forbes    if (!pPipeline->graphicsPipelineCI.pRasterizationState ||
254929d196e071b2dc1db47702085469396f2b956820Chris Forbes        (pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable == VK_FALSE)) {
255029d196e071b2dc1db47702085469396f2b956820Chris Forbes        VkSampleCountFlagBits pso_num_samples = getNumSamples(pPipeline);
255129d196e071b2dc1db47702085469396f2b956820Chris Forbes        if (pCB->activeRenderPass) {
2552fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes            auto const render_pass_info = pCB->activeRenderPass->createInfo.ptr();
255329d196e071b2dc1db47702085469396f2b956820Chris Forbes            const VkSubpassDescription *subpass_desc = &render_pass_info->pSubpasses[pCB->activeSubpass];
255429d196e071b2dc1db47702085469396f2b956820Chris Forbes            uint32_t i;
255576957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes            unsigned subpass_num_samples = 0;
25560a7ed0466d3d3c6c71be07d66c200482d9a9d073Chris Forbes
255729d196e071b2dc1db47702085469396f2b956820Chris Forbes            for (i = 0; i < subpass_desc->colorAttachmentCount; i++) {
255876957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                auto attachment = subpass_desc->pColorAttachments[i].attachment;
255976957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                if (attachment != VK_ATTACHMENT_UNUSED)
256076957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                    subpass_num_samples |= (unsigned)render_pass_info->pAttachments[attachment].samples;
256129d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
25620a7ed0466d3d3c6c71be07d66c200482d9a9d073Chris Forbes
256376957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes            if (subpass_desc->pDepthStencilAttachment &&
256476957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                subpass_desc->pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
256576957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                auto attachment = subpass_desc->pDepthStencilAttachment->attachment;
256676957dd352738b7ceec82c38be8b1b1347a90040Chris Forbes                subpass_num_samples |= (unsigned)render_pass_info->pAttachments[attachment].samples;
256729d196e071b2dc1db47702085469396f2b956820Chris Forbes            }
2568eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
25690dc3fd4e57b8531638781daa01a2fb5d1048a6fbJamie Madill            if (subpass_num_samples && static_cast<unsigned>(pso_num_samples) != subpass_num_samples) {
25703251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
25719b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pPipeline->pipeline), __LINE__, DRAWSTATE_NUM_SAMPLES_MISMATCH, "DS",
25729b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "Num samples mismatch! At draw-time in Pipeline (0x%" PRIxLEAST64
25739b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                ") with %u samples while current RenderPass (0x%" PRIxLEAST64 ") w/ %u samples!",
25749b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pPipeline->pipeline), pso_num_samples,
25759b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pCB->activeRenderPass->renderPass), subpass_num_samples);
2576eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young            }
257729d196e071b2dc1db47702085469396f2b956820Chris Forbes        } else {
25783251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
25799b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pPipeline->pipeline), __LINE__, DRAWSTATE_NUM_SAMPLES_MISMATCH, "DS",
25803251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "No active render pass found at draw-time in Pipeline (0x%" PRIxLEAST64 ")!",
25819b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pPipeline->pipeline));
2582eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young        }
2583eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    }
2584528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis    // Verify that PSO creation renderPass is compatible with active renderPass
2585528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis    if (pCB->activeRenderPass) {
2586528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis        std::string err_string;
2587a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        if ((pCB->activeRenderPass->renderPass != pPipeline->graphicsPipelineCI.renderPass) &&
258851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            !verify_renderpass_compatibility(dev_data, pCB->activeRenderPass->createInfo.ptr(), pPipeline->render_pass_ci.ptr(),
2589528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis                                             err_string)) {
2590528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis            // renderPass that PSO was created with must be compatible with active renderPass that PSO is being used with
25913251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
25929b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pPipeline->pipeline), __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE, "DS",
25939b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "At Draw time the active render pass (0x%" PRIxLEAST64
25949b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            ") is incompatible w/ gfx pipeline "
25959b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "(0x%" PRIxLEAST64 ") that was created w/ render pass (0x%" PRIxLEAST64 ") due to: %s",
25969b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pCB->activeRenderPass->renderPass), HandleToUint64(pPipeline->pipeline),
25979b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pPipeline->graphicsPipelineCI.renderPass), err_string.c_str());
2598528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis        }
2599c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes
2600c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes        if (pPipeline->graphicsPipelineCI.subpass != pCB->activeSubpass) {
26013251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
26029b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pPipeline->pipeline), __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE, "DS",
26039b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "Pipeline was built for subpass %u but used in subpass %u", pPipeline->graphicsPipelineCI.subpass,
26043251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            pCB->activeSubpass);
2605c307df2953e6b023531a6ef7fd11e3ee2f2c58b0Chris Forbes        }
2606528f623d935b0ab102a2f9c1c82787a8810ca360Tobin Ehlis    }
260729d196e071b2dc1db47702085469396f2b956820Chris Forbes    // TODO : Add more checks here
260829d196e071b2dc1db47702085469396f2b956820Chris Forbes
26093251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
2610eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young}
2611eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
26125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Validate overall state at the time of a draw call
261351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool ValidateDrawState(layer_data *dev_data, GLOBAL_CB_NODE *cb_node, const bool indexed,
26144f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                              const VkPipelineBindPoint bind_point, const char *function,
26154f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes                              UNIQUE_VALIDATION_ERROR_CODE const msg_code) {
2616e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool result = false;
26171c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    auto const &state = cb_node->lastBound[bind_point];
26184c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    PIPELINE_STATE *pPipe = state.pipeline_state;
261922fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis    if (nullptr == pPipe) {
262022fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis        result |= log_msg(
2621df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
26229b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus            HandleToUint64(cb_node->commandBuffer), __LINE__, DRAWSTATE_INVALID_PIPELINE, "DS",
262322fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis            "At Draw/Dispatch time no valid VkPipeline is bound! This is illegal. Please bind one with vkCmdBindPipeline().");
262422fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis        // Early return as any further checks below will be busted w/o a pipeline
2625cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (result) return true;
262622fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis    }
26273d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    // First check flag states
26281c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    if (VK_PIPELINE_BIND_POINT_GRAPHICS == bind_point)
262951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        result = validate_draw_state_flags(dev_data, cb_node, pPipe, indexed, msg_code);
26307a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis
26315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Now complete other state checks
263269b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis    if (VK_NULL_HANDLE != state.pipeline_layout.layout) {
263322fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis        string errorString;
263469b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis        auto pipeline_layout = pPipe->pipeline_layout;
2635169c4506062f06d6676eb4da3c9e0437d1d9d659Chris Forbes
26361c130ea631a82716dc7334de17767536525f2292Tobin Ehlis        for (const auto &set_binding_pair : pPipe->active_slots) {
26371c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            uint32_t setIndex = set_binding_pair.first;
263822fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis            // If valid set is not bound throw an error
263922fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis            if ((state.boundDescriptorSets.size() <= setIndex) || (!state.boundDescriptorSets[setIndex])) {
26409b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                result |=
26419b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
26429b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(cb_node->commandBuffer), __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_BOUND, "DS",
26439b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "VkPipeline 0x%" PRIxLEAST64 " uses set #%u but that set is not bound.",
26449b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pPipe->pipeline), setIndex);
264512b7fc342b53fbdd399aae4a85959e37685936acChris Forbes            } else if (!verify_set_layout_compatibility(state.boundDescriptorSets[setIndex], &pipeline_layout, setIndex,
264669b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                                                        errorString)) {
264769b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis                // Set is bound but not compatible w/ overlapping pipeline_layout from PSO
264871511c5a10533c910bfe62c3bcf58e2a4054e7acTobin Ehlis                VkDescriptorSet setHandle = state.boundDescriptorSets[setIndex]->GetSet();
264922fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                result |=
265051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
26519b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(setHandle), __LINE__, DRAWSTATE_PIPELINE_LAYOUTS_INCOMPATIBLE, "DS",
2652414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                            "VkDescriptorSet (0x%" PRIxLEAST64
2653414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                            ") bound as set #%u is not compatible with overlapping VkPipelineLayout 0x%" PRIxLEAST64 " due to: %s",
26549b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(setHandle), setIndex, HandleToUint64(pipeline_layout.layout), errorString.c_str());
2655cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else {  // Valid set is bound and layout compatible, validate that it's updated
265622fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis                // Pull the set node
26571c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                cvdescriptorset::DescriptorSet *descriptor_set = state.boundDescriptorSets[setIndex];
26587433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis                // Validate the draw-time state for this descriptor set
26597433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis                std::string err_str;
26600db18ab1345f9e10907913b22ea5d57bd48077ebTobin Ehlis                if (!descriptor_set->ValidateDrawState(set_binding_pair.second, state.dynamicOffsets[setIndex], cb_node, function,
26610db18ab1345f9e10907913b22ea5d57bd48077ebTobin Ehlis                                                       &err_str)) {
26621c130ea631a82716dc7334de17767536525f2292Tobin Ehlis                    auto set = descriptor_set->GetSet();
26630db18ab1345f9e10907913b22ea5d57bd48077ebTobin Ehlis                    result |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
26649b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                      VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, HandleToUint64(set), __LINE__,
26659b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                      DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS",
26660db18ab1345f9e10907913b22ea5d57bd48077ebTobin Ehlis                                      "Descriptor set 0x%" PRIxLEAST64 " encountered the following validation error at %s time: %s",
26679b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                      HandleToUint64(set), function, err_str.c_str());
26687433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis                }
26695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
267022fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis        }
267122fb3c0393ef588b11f8313f01c508028d77dec0Tobin Ehlis    }
2672eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
2673eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young    // Check general pipeline state that needs to be validated at drawtime
267451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (VK_PIPELINE_BIND_POINT_GRAPHICS == bind_point) result |= ValidatePipelineDrawtimeState(dev_data, state, cb_node, pPipe);
2675eca2d52a6bfa3f9d63a86ca9fd30abc0adf775b7Mark Young
26765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
26775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
26785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
267951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void UpdateDrawState(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, const VkPipelineBindPoint bind_point) {
26801c130ea631a82716dc7334de17767536525f2292Tobin Ehlis    auto const &state = cb_state->lastBound[bind_point];
2681ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis    PIPELINE_STATE *pPipe = state.pipeline_state;
2682ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis    if (VK_NULL_HANDLE != state.pipeline_layout.layout) {
26831c130ea631a82716dc7334de17767536525f2292Tobin Ehlis        for (const auto &set_binding_pair : pPipe->active_slots) {
26841c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            uint32_t setIndex = set_binding_pair.first;
2685ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis            // Pull the set node
26861c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            cvdescriptorset::DescriptorSet *descriptor_set = state.boundDescriptorSets[setIndex];
2687ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis            // Bind this set and its active descriptor resources to the command buffer
26881c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            descriptor_set->BindCommandBuffer(cb_state, set_binding_pair.second);
26897433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis            // For given active slots record updated images & buffers
26901c130ea631a82716dc7334de17767536525f2292Tobin Ehlis            descriptor_set->GetStorageUpdates(set_binding_pair.second, &cb_state->updateBuffers, &cb_state->updateImages);
2691ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis        }
2692ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis    }
269358b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    if (pPipe->vertexBindingDescriptions.size() > 0) {
269458b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis        cb_state->vertex_buffer_used = true;
269558b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    }
2696ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis}
2697ec2ff49aea47929f28679d7bbe598ec439db7bb5Tobin Ehlis
2698a27508babf63d50aea75883a3702979193c23683Mark Young// Validate HW line width capabilities prior to setting requested line width.
269906727c7f56d1080aff506a9ae1ae9d8c174b3e9dMark Lobodzinskistatic bool verifyLineWidth(layer_data *dev_data, DRAW_STATE_ERROR dsError, VulkanObjectType object_type, const uint64_t &target,
270006727c7f56d1080aff506a9ae1ae9d8c174b3e9dMark Lobodzinski                            float lineWidth) {
27013251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
2702a27508babf63d50aea75883a3702979193c23683Mark Young
2703a27508babf63d50aea75883a3702979193c23683Mark Young    // First check to see if the physical device supports wide lines.
270451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if ((VK_FALSE == dev_data->enabled_features.wideLines) && (1.0f != lineWidth)) {
27053251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, get_debug_report_enum[object_type], target, __LINE__,
27063251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        dsError, "DS",
27073251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Attempt to set lineWidth to %f but physical device wideLines feature "
27083251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "not supported/enabled so lineWidth must be 1.0f!",
27093251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        lineWidth);
2710a27508babf63d50aea75883a3702979193c23683Mark Young    } else {
2711a27508babf63d50aea75883a3702979193c23683Mark Young        // Otherwise, make sure the width falls in the valid range.
271251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        if ((dev_data->phys_dev_properties.properties.limits.lineWidthRange[0] > lineWidth) ||
271351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            (dev_data->phys_dev_properties.properties.limits.lineWidthRange[1] < lineWidth)) {
27143251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, get_debug_report_enum[object_type], target,
27153251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            __LINE__, dsError, "DS",
27163251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Attempt to set lineWidth to %f but physical device limits line width "
27173251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "to between [%f, %f]!",
27183251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            lineWidth, dev_data->phys_dev_properties.properties.limits.lineWidthRange[0],
27193251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            dev_data->phys_dev_properties.properties.limits.lineWidthRange[1]);
2720a27508babf63d50aea75883a3702979193c23683Mark Young        }
2721a27508babf63d50aea75883a3702979193c23683Mark Young    }
2722a27508babf63d50aea75883a3702979193c23683Mark Young
27233251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
2724a27508babf63d50aea75883a3702979193c23683Mark Young}
2725a27508babf63d50aea75883a3702979193c23683Mark Young
27265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Verify that create state for a pipeline is valid
272751ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool verifyPipelineCreateState(layer_data *dev_data, std::vector<PIPELINE_STATE *> pPipelines, int pipelineIndex) {
27283251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
27295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27304c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    PIPELINE_STATE *pPipeline = pPipelines[pipelineIndex];
27315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If create derivative bit is set, check that we've specified a base
27335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // pipeline correctly, and that the base pipeline was created to allow
27345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // derivatives.
27355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pPipeline->graphicsPipelineCI.flags & VK_PIPELINE_CREATE_DERIVATIVE_BIT) {
27364c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis        PIPELINE_STATE *pBasePipeline = nullptr;
27375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!((pPipeline->graphicsPipelineCI.basePipelineHandle != VK_NULL_HANDLE) ^
27385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis              (pPipeline->graphicsPipelineCI.basePipelineIndex != -1))) {
2739315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            // This check is a superset of VALIDATION_ERROR_096005a8 and VALIDATION_ERROR_096005aa
27403251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
27419b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pPipeline->pipeline), __LINE__, DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
27429b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "Invalid Pipeline CreateInfo: exactly one of base pipeline index and handle must be specified");
27435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (pPipeline->graphicsPipelineCI.basePipelineIndex != -1) {
27445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (pPipeline->graphicsPipelineCI.basePipelineIndex >= pipelineIndex) {
27453251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
2746df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2747315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_208005a0, "DS",
2748f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                            "Invalid Pipeline CreateInfo: base pipeline must occur earlier in array than derivative pipeline. %s",
2749315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_208005a0]);
27505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else {
27515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pBasePipeline = pPipelines[pPipeline->graphicsPipelineCI.basePipelineIndex];
27525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
27535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (pPipeline->graphicsPipelineCI.basePipelineHandle != VK_NULL_HANDLE) {
275451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            pBasePipeline = getPipelineState(dev_data, pPipeline->graphicsPipelineCI.basePipelineHandle);
27555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
27565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (pBasePipeline && !(pBasePipeline->graphicsPipelineCI.flags & VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT)) {
27583251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
27599b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pPipeline->pipeline), __LINE__, DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
27609b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "Invalid Pipeline CreateInfo: base pipeline does not allow derivatives.");
27615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
27625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
27635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
27645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pPipeline->graphicsPipelineCI.pColorBlendState != NULL) {
2765fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis        const safe_VkPipelineColorBlendStateCreateInfo *color_blend_state = pPipeline->graphicsPipelineCI.pColorBlendState;
27669a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto const render_pass_info = GetRenderPassState(dev_data, pPipeline->graphicsPipelineCI.renderPass)->createInfo.ptr();
2767fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis        const VkSubpassDescription *subpass_desc = &render_pass_info->pSubpasses[pPipeline->graphicsPipelineCI.subpass];
2768fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis        if (color_blend_state->attachmentCount != subpass_desc->colorAttachmentCount) {
27693251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(
277051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2771315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_096005d4, "DS",
2772fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis                "vkCreateGraphicsPipelines(): Render pass (0x%" PRIxLEAST64
2773fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis                ") subpass %u has colorAttachmentCount of %u which doesn't match the pColorBlendState->attachmentCount of %u. %s",
27749b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                HandleToUint64(pPipeline->graphicsPipelineCI.renderPass), pPipeline->graphicsPipelineCI.subpass,
2775fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis                subpass_desc->colorAttachmentCount, color_blend_state->attachmentCount,
2776315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                validation_error_map[VALIDATION_ERROR_096005d4]);
2777fb4e70f35eef785ce77fca908d4d64f60539893dTobin Ehlis        }
277851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        if (!dev_data->enabled_features.independentBlend) {
27793d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis            if (pPipeline->attachments.size() > 1) {
278026c548826ff0f83d12c769b51e7d6f76d1265c0eChris Forbes                VkPipelineColorBlendAttachmentState *pAttachments = &pPipeline->attachments[0];
2781c7bd67f06427b08ba65cdf2dd529c8234beebdd5Mark Lobodzinski                for (size_t i = 1; i < pPipeline->attachments.size(); i++) {
278206811df0256552cd7da9d7297672af377463fc4aMark Mueller                    // Quoting the spec: "If [the independent blend] feature is not enabled, the VkPipelineColorBlendAttachmentState
278306811df0256552cd7da9d7297672af377463fc4aMark Mueller                    // settings for all color attachments must be identical." VkPipelineColorBlendAttachmentState contains
278406811df0256552cd7da9d7297672af377463fc4aMark Mueller                    // only attachment state, so memcmp is best suited for the comparison
278506811df0256552cd7da9d7297672af377463fc4aMark Mueller                    if (memcmp(static_cast<const void *>(pAttachments), static_cast<const void *>(&pAttachments[i]),
278606811df0256552cd7da9d7297672af377463fc4aMark Mueller                               sizeof(pAttachments[0]))) {
27873251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        skip |=
2788df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2789315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_0f4004ba, "DS",
2790df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    "Invalid Pipeline CreateInfo: If independent blend feature not "
2791df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                    "enabled, all elements of pAttachments must be identical. %s",
2792315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    validation_error_map[VALIDATION_ERROR_0f4004ba]);
279306811df0256552cd7da9d7297672af377463fc4aMark Mueller                        break;
2794c7bd67f06427b08ba65cdf2dd529c8234beebdd5Mark Lobodzinski                    }
27955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
27965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
27975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
279851ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        if (!dev_data->enabled_features.logicOp && (pPipeline->graphicsPipelineCI.pColorBlendState->logicOpEnable != VK_FALSE)) {
27993251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |=
2800df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2801315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_0f4004bc, "DS",
2802f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt                        "Invalid Pipeline CreateInfo: If logic operations feature not enabled, logicOpEnable must be VK_FALSE. %s",
2803315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_0f4004bc]);
28045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
28055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
28065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
2807a61b537fcb6a4f7b92cd217b3964ad7a48109da1Tobin Ehlis    // Ensure the subpass index is valid. If not, then validate_and_capture_pipeline_shader_state
28085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // produces nonsense errors that confuse users. Other layers should already
28095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // emit errors for renderpass being invalid.
28109a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto renderPass = GetRenderPassState(dev_data, pPipeline->graphicsPipelineCI.renderPass);
2811fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    if (renderPass && pPipeline->graphicsPipelineCI.subpass >= renderPass->createInfo.subpassCount) {
28123251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2813315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_096005ee, "DS",
28143251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Invalid Pipeline CreateInfo State: Subpass index %u "
28153251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "is out of range for this renderpass (0..%u). %s",
28163251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        pPipeline->graphicsPipelineCI.subpass, renderPass->createInfo.subpassCount - 1,
2817315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_096005ee]);
28185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
28195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
282059ae0ccadec962d9ca2cce7584fad6c57c1a4458Tobin Ehlis    if (validate_and_capture_pipeline_shader_state(dev_data, pPipeline)) {
28213251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip = true;
28225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
282352156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes    // Each shader's stage must be unique
282452156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes    if (pPipeline->duplicate_shaders) {
282552156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes        for (uint32_t stage = VK_SHADER_STAGE_VERTEX_BIT; stage & VK_SHADER_STAGE_ALL_GRAPHICS; stage <<= 1) {
282652156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes            if (pPipeline->duplicate_shaders & stage) {
28279b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
28289b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pPipeline->pipeline), __LINE__, DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
28299b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "Invalid Pipeline CreateInfo State: Multiple shaders provided for stage %s",
28309b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                string_VkShaderStageFlagBits(VkShaderStageFlagBits(stage)));
283152156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes            }
283252156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes        }
283352156ec29c88c0e52eb89fb42867adacb1dd31bbChris Forbes    }
28345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // VS is required
28355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (!(pPipeline->active_shaders & VK_SHADER_STAGE_VERTEX_BIT)) {
2836315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2837315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_096005ae, "DS",
2838315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        "Invalid Pipeline CreateInfo State: Vertex Shader required. %s",
2839315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_096005ae]);
28405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
28415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Either both or neither TC/TE shaders should be defined
28423067e46adf202d2cc3ce1e06909dc7fadf0c8c3bCort Stratton    bool has_control = (pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) != 0;
28433067e46adf202d2cc3ce1e06909dc7fadf0c8c3bCort Stratton    bool has_eval = (pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) != 0;
28443067e46adf202d2cc3ce1e06909dc7fadf0c8c3bCort Stratton    if (has_control && !has_eval) {
28453251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2846315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_096005b2, "DS",
28473251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Invalid Pipeline CreateInfo State: TE and TC shaders must be included or excluded as a pair. %s",
2848315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_096005b2]);
2849f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    }
28503067e46adf202d2cc3ce1e06909dc7fadf0c8c3bCort Stratton    if (!has_control && has_eval) {
28513251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2852315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_096005b4, "DS",
28533251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Invalid Pipeline CreateInfo State: TE and TC shaders must be included or excluded as a pair. %s",
2854315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_096005b4]);
28555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
28565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Compute shaders should be specified independent of Gfx shaders
2857f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt    if (pPipeline->active_shaders & VK_SHADER_STAGE_COMPUTE_BIT) {
28583251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2859315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_096005b0, "DS",
28603251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Invalid Pipeline CreateInfo State: Do not specify Compute Shader for Gfx Pipeline. %s",
2861315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_096005b0]);
28625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
28635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive topology is only valid for tessellation pipelines.
28645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Mismatching primitive topology and tessellation fails graphics pipeline creation.
28653067e46adf202d2cc3ce1e06909dc7fadf0c8c3bCort Stratton    if (has_control && has_eval &&
2866ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        (!pPipeline->graphicsPipelineCI.pInputAssemblyState ||
2867ca546210846c65808717f8875deae39bd227c240Tobin Ehlis         pPipeline->graphicsPipelineCI.pInputAssemblyState->topology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST)) {
28683251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2869315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_096005c0, "DS",
28703251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Invalid Pipeline CreateInfo State: "
28713251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST must be set as IA "
28723251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "topology for tessellation pipelines. %s",
2873315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_096005c0]);
28745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2875ca546210846c65808717f8875deae39bd227c240Tobin Ehlis    if (pPipeline->graphicsPipelineCI.pInputAssemblyState &&
2876ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        pPipeline->graphicsPipelineCI.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) {
28773067e46adf202d2cc3ce1e06909dc7fadf0c8c3bCort Stratton        if (!has_control || !has_eval) {
28783251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2879315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_096005c2, "DS",
28803251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Invalid Pipeline CreateInfo State: "
28813251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive "
28823251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "topology is only valid for tessellation pipelines. %s",
2883315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_096005c2]);
28845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
28855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2886f62c50f00d7d03e27fbc3769e582761e8a4944ddMike Schuchardt
28876b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen    // If a rasterization state is provided...
2888a27508babf63d50aea75883a3702979193c23683Mark Young    if (pPipeline->graphicsPipelineCI.pRasterizationState) {
28896b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen        // Make sure that the line width conforms to the HW.
2890a27508babf63d50aea75883a3702979193c23683Mark Young        if (!isDynamic(pPipeline, VK_DYNAMIC_STATE_LINE_WIDTH)) {
28919b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus            skip |=
28929b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                verifyLineWidth(dev_data, DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, kVulkanObjectTypePipeline,
28939b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pPipeline->pipeline), pPipeline->graphicsPipelineCI.pRasterizationState->lineWidth);
2894a27508babf63d50aea75883a3702979193c23683Mark Young        }
28955dcdd90e54199dfeb29938a3a03d998397c22664Chris Forbes
289658c5552c73679f81f57a64a809f7d4d6d52f4ce3Mark Lobodzinski        if ((pPipeline->graphicsPipelineCI.pRasterizationState->depthClampEnable == VK_TRUE) &&
289758c5552c73679f81f57a64a809f7d4d6d52f4ce3Mark Lobodzinski            (!dev_data->enabled_features.depthClamp)) {
28983251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2899315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_1020061c, "DS",
29003251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkCreateGraphicsPipelines(): the depthClamp device feature is disabled: the depthClampEnable "
29013251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "member of the VkPipelineRasterizationStateCreateInfo structure must be set to VK_FALSE. %s",
2902315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_1020061c]);
290358c5552c73679f81f57a64a809f7d4d6d52f4ce3Mark Lobodzinski        }
290458c5552c73679f81f57a64a809f7d4d6d52f4ce3Mark Lobodzinski
2905434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski        if (!isDynamic(pPipeline, VK_DYNAMIC_STATE_DEPTH_BIAS) &&
2906434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski            (pPipeline->graphicsPipelineCI.pRasterizationState->depthBiasClamp != 0.0) &&
2907434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski            (!dev_data->enabled_features.depthBiasClamp)) {
29083251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
29099b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pPipeline->pipeline), __LINE__, DRAWSTATE_INVALID_FEATURE, "DS",
29103251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkCreateGraphicsPipelines(): the depthBiasClamp device feature is disabled: the depthBiasClamp "
29113251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "member of the VkPipelineRasterizationStateCreateInfo structure must be set to 0.0 unless the "
29123251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "VK_DYNAMIC_STATE_DEPTH_BIAS dynamic state is enabled");
2913434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski        }
2914434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski
29156b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen        // If rasterization is enabled...
29166b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen        if (pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable == VK_FALSE) {
29176b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen            auto subpass_desc = renderPass ? &renderPass->createInfo.pSubpasses[pPipeline->graphicsPipelineCI.subpass] : nullptr;
29186b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen
2919148e8028deee2b4b00ccd4a69210897add328265Mark Lobodzinski            if ((pPipeline->graphicsPipelineCI.pMultisampleState->alphaToOneEnable == VK_TRUE) &&
2920148e8028deee2b4b00ccd4a69210897add328265Mark Lobodzinski                (!dev_data->enabled_features.alphaToOne)) {
29213251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2922315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_10000622, "DS",
29233251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "vkCreateGraphicsPipelines(): the alphaToOne device feature is disabled: the alphaToOneEnable "
29243251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "member of the VkPipelineMultisampleStateCreateInfo structure must be set to VK_FALSE. %s",
2925315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                validation_error_map[VALIDATION_ERROR_10000622]);
2926148e8028deee2b4b00ccd4a69210897add328265Mark Lobodzinski            }
2927148e8028deee2b4b00ccd4a69210897add328265Mark Lobodzinski
29286b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen            // If subpass uses a depth/stencil attachment, pDepthStencilState must be a pointer to a valid structure
29296b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen            if (subpass_desc && subpass_desc->pDepthStencilAttachment &&
29306b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen                subpass_desc->pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
29316b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen                if (!pPipeline->graphicsPipelineCI.pDepthStencilState) {
29323251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2933315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_096005e0, "DS",
29343251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "Invalid Pipeline CreateInfo State: pDepthStencilState is NULL when rasterization is "
29353251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "enabled and subpass uses a depth/stencil attachment. %s",
2936315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    validation_error_map[VALIDATION_ERROR_096005e0]);
29379580629edfc5154cc9e36974cca12966fbd748b9Mark Lobodzinski
29389580629edfc5154cc9e36974cca12966fbd748b9Mark Lobodzinski                } else if ((pPipeline->graphicsPipelineCI.pDepthStencilState->depthBoundsTestEnable == VK_TRUE) &&
29399580629edfc5154cc9e36974cca12966fbd748b9Mark Lobodzinski                           (!dev_data->enabled_features.depthBounds)) {
29403251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(
2941df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
29429b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(pPipeline->pipeline), __LINE__, DRAWSTATE_INVALID_FEATURE, "DS",
29439580629edfc5154cc9e36974cca12966fbd748b9Mark Lobodzinski                        "vkCreateGraphicsPipelines(): the depthBounds device feature is disabled: the depthBoundsTestEnable "
29449580629edfc5154cc9e36974cca12966fbd748b9Mark Lobodzinski                        "member of the VkPipelineDepthStencilStateCreateInfo structure must be set to VK_FALSE.");
29456b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen                }
29465dcdd90e54199dfeb29938a3a03d998397c22664Chris Forbes            }
2947326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen
2948326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen            // If subpass uses color attachments, pColorBlendState must be valid pointer
2949326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen            if (subpass_desc) {
2950326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                uint32_t color_attachment_count = 0;
2951326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                for (uint32_t i = 0; i < subpass_desc->colorAttachmentCount; ++i) {
2952326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                    if (subpass_desc->pColorAttachments[i].attachment != VK_ATTACHMENT_UNUSED) {
2953326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                        ++color_attachment_count;
2954326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                    }
2955326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                }
2956326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                if (color_attachment_count > 0 && pPipeline->graphicsPipelineCI.pColorBlendState == nullptr) {
29573251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2958315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    HandleToUint64(pPipeline->pipeline), __LINE__, VALIDATION_ERROR_096005e2, "DS",
29593251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "Invalid Pipeline CreateInfo State: pColorBlendState is NULL when rasterization is "
29603251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "enabled and subpass uses color attachments. %s",
2961315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    validation_error_map[VALIDATION_ERROR_096005e2]);
2962326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen                }
2963326fc9f00659303e0a5b3fc4019db2bda641c7bdMike Weiblen            }
29645dcdd90e54199dfeb29938a3a03d998397c22664Chris Forbes        }
29655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
29666b8d2b83e8400e5238705a0856b5e3acff8df742Mike Weiblen
29673251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
29685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
29695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
29705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Free the Pipeline nodes
297151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void deletePipelines(layer_data *dev_data) {
297251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (dev_data->pipelineMap.size() <= 0) return;
297351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    for (auto &pipe_map_pair : dev_data->pipelineMap) {
2974ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        delete pipe_map_pair.second;
29755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
297651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    dev_data->pipelineMap.clear();
29775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
29785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
29795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Block of code at start here specifically for managing/tracking DSs
29805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
29815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Return Pool node ptr for specified pool or else NULL
29829a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisDESCRIPTOR_POOL_STATE *GetDescriptorPoolState(const layer_data *dev_data, const VkDescriptorPool pool) {
2983bb7ea477706f90eb2a72887f652795bc79f60ddeTobin Ehlis    auto pool_it = dev_data->descriptorPoolMap.find(pool);
2984bb7ea477706f90eb2a72887f652795bc79f60ddeTobin Ehlis    if (pool_it == dev_data->descriptorPoolMap.end()) {
29855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return NULL;
29865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
2987bb7ea477706f90eb2a72887f652795bc79f60ddeTobin Ehlis    return pool_it->second;
29885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
29895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
29905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Validate that given set is valid and that it's not being used by an in-flight CmdBuffer
29915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// func_str is the name of the calling function
2992e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves// Return false if no errors occur
2993e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves// Return true if validation error occurs and callback returns true (to skip upcoming API call down the chain)
29940dcd0f7b37456e2e552d37094ba503c0d089b906Tobin Ehlisstatic bool validateIdleDescriptorSet(const layer_data *dev_data, VkDescriptorSet set, std::string func_str) {
2995cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.idle_descriptor_set) return false;
29963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
29970dcd0f7b37456e2e552d37094ba503c0d089b906Tobin Ehlis    auto set_node = dev_data->setMap.find(set);
29980dcd0f7b37456e2e552d37094ba503c0d089b906Tobin Ehlis    if (set_node == dev_data->setMap.end()) {
29993251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
30009b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(set), __LINE__, DRAWSTATE_DOUBLE_DESTROY, "DS",
30013251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Cannot call %s() on descriptor set 0x%" PRIxLEAST64 " that has not been allocated.", func_str.c_str(),
30029b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(set));
30035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
30041c48e214b2ed50690da7f42f2013be3a6ef267dfTobin Ehlis        // TODO : This covers various error cases so should pass error enum into this function and use passed in enum here
30055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (set_node->second->in_use.load()) {
30063251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
3007315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(set), __LINE__, VALIDATION_ERROR_2860026a, "DS",
30083251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Cannot call %s() on descriptor set 0x%" PRIxLEAST64 " that is in use by a command buffer. %s",
3009315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            func_str.c_str(), HandleToUint64(set), validation_error_map[VALIDATION_ERROR_2860026a]);
30105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
30115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
30123251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
30135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
3014f80bf38f4fb3f177b3e1be11b7b1c5edcdbf7d9bChris Forbes
3015e6651096ed8f07840447783c66827cc16d659a49Tobin Ehlis// Remove set from setMap and delete the set
30169dd448578d59cb5ce692e833ba230783b30f3550Tobin Ehlisstatic void freeDescriptorSet(layer_data *dev_data, cvdescriptorset::DescriptorSet *descriptor_set) {
30179dd448578d59cb5ce692e833ba230783b30f3550Tobin Ehlis    dev_data->setMap.erase(descriptor_set->GetSet());
30189dd448578d59cb5ce692e833ba230783b30f3550Tobin Ehlis    delete descriptor_set;
30199dd448578d59cb5ce692e833ba230783b30f3550Tobin Ehlis}
30205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Free all DS Pools including their Sets & related sub-structs
30215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// NOTE : Calls to this function should be wrapped in mutex
302251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void deletePools(layer_data *dev_data) {
3023ee7e96d032744c1db89cab21362ac8ecad6eec5aGabríel Arthúr Pétursson    for (auto ii = dev_data->descriptorPoolMap.begin(); ii != dev_data->descriptorPoolMap.end();) {
3024c5f47f0a54e14c47d402aeabc6498d981ecda9ccTobin Ehlis        // Remove this pools' sets from setMap and delete them
3025ee7e96d032744c1db89cab21362ac8ecad6eec5aGabríel Arthúr Pétursson        for (auto ds : ii->second->sets) {
302651ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis            freeDescriptorSet(dev_data, ds);
30275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
3028ee7e96d032744c1db89cab21362ac8ecad6eec5aGabríel Arthúr Pétursson        ii->second->sets.clear();
3029ee7e96d032744c1db89cab21362ac8ecad6eec5aGabríel Arthúr Pétursson        delete ii->second;
3030ee7e96d032744c1db89cab21362ac8ecad6eec5aGabríel Arthúr Pétursson        ii = dev_data->descriptorPoolMap.erase(ii);
30315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
30325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
30335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
303451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void clearDescriptorPool(layer_data *dev_data, const VkDevice device, const VkDescriptorPool pool,
30355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                                VkDescriptorPoolResetFlags flags) {
30369a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DESCRIPTOR_POOL_STATE *pPool = GetDescriptorPoolState(dev_data, pool);
3037de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    // TODO: validate flags
3038de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    // For every set off of this pool, clear it, remove from setMap, and free cvdescriptorset::DescriptorSet
3039de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    for (auto ds : pPool->sets) {
304051ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        freeDescriptorSet(dev_data, ds);
3041de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    }
3042de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    pPool->sets.clear();
3043de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    // Reset available count for each type and available sets for this pool
3044de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    for (uint32_t i = 0; i < pPool->availableDescriptorTypeCount.size(); ++i) {
3045de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis        pPool->availableDescriptorTypeCount[i] = pPool->maxDescriptorTypeCount[i];
30465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
3047de7672b6b749c09c5991bd8038b3a35ef82a69dcTobin Ehlis    pPool->availableSets = pPool->maxSets;
30485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
30495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
30505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// For given CB object, fetch associated CB Node from map
30519a9a0db2a973034d4286b6d4c62a46beb7641791Tobin EhlisGLOBAL_CB_NODE *GetCBNode(layer_data const *dev_data, const VkCommandBuffer cb) {
305251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto it = dev_data->commandBufferMap.find(cb);
305351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (it == dev_data->commandBufferMap.end()) {
30545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return NULL;
30555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
30565121a8dcacb23766ba4455b4eea429f0a3d62099Chris Forbes    return it->second;
30575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
30585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
305929f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis// If a renderpass is active, verify that the given command type is appropriate for current subpass state
306029f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlisbool ValidateCmdSubpassState(const layer_data *dev_data, const GLOBAL_CB_NODE *pCB, const CMD_TYPE cmd_type) {
3061cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!pCB->activeRenderPass) return false;
30623251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
3063d0d8e333806eaac08bdc87ddeff886dc2b0f09e7Tobin Ehlis    if (pCB->activeSubpassContents == VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS &&
3064d0d8e333806eaac08bdc87ddeff886dc2b0f09e7Tobin Ehlis        (cmd_type != CMD_EXECUTECOMMANDS && cmd_type != CMD_NEXTSUBPASS && cmd_type != CMD_ENDRENDERPASS)) {
30653251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
30669b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
30673251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Commands cannot be called in a subpass using secondary command buffers.");
30685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else if (pCB->activeSubpassContents == VK_SUBPASS_CONTENTS_INLINE && cmd_type == CMD_EXECUTECOMMANDS) {
30693251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
30709b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
30713251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkCmdExecuteCommands() cannot be called in a subpass using inline commands.");
30725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
30733251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
30745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
30755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3076baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardtbool ValidateCmdQueueFlags(layer_data *dev_data, GLOBAL_CB_NODE *cb_node, const char *caller_name, VkQueueFlags required_flags,
3077baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                           UNIQUE_VALIDATION_ERROR_CODE error_code) {
3078baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    auto pool = GetCommandPoolNode(dev_data, cb_node->createInfo.commandPool);
3079baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    if (pool) {
3080baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        VkQueueFlags queue_flags = dev_data->phys_dev_properties.queue_family_properties[pool->queueFamilyIndex].queueFlags;
3081baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        if (!(required_flags & queue_flags)) {
3082baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt            string required_flags_string;
3083baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt            for (auto flag : {VK_QUEUE_TRANSFER_BIT, VK_QUEUE_GRAPHICS_BIT, VK_QUEUE_COMPUTE_BIT}) {
3084baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                if (flag & required_flags) {
3085baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                    if (required_flags_string.size()) {
3086baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                        required_flags_string += " or ";
3087baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                    }
3088baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                    required_flags_string += string_VkQueueFlagBits(flag);
3089baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                }
3090baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt            }
3091baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt            return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
30929b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                           HandleToUint64(cb_node->commandBuffer), __LINE__, error_code, "DS",
3093baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                           "Cannot call %s on a command buffer allocated from a pool without %s capabilities. %s.", caller_name,
3094baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                           required_flags_string.c_str(), validation_error_map[error_code]);
3095baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        }
3096baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    }
30975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return false;
30985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
30995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3100d00947f5dcd29a4d8aab59e62f72df50444d2537Chris Forbesstatic char const * GetCauseStr(VK_OBJECT obj) {
3101d00947f5dcd29a4d8aab59e62f72df50444d2537Chris Forbes    if (obj.type == kVulkanObjectTypeDescriptorSet)
3102d00947f5dcd29a4d8aab59e62f72df50444d2537Chris Forbes        return "destroyed or updated";
3103d00947f5dcd29a4d8aab59e62f72df50444d2537Chris Forbes    if (obj.type == kVulkanObjectTypeCommandBuffer)
3104d00947f5dcd29a4d8aab59e62f72df50444d2537Chris Forbes        return "destroyed or rerecorded";
3105d00947f5dcd29a4d8aab59e62f72df50444d2537Chris Forbes    return "destroyed";
3106d00947f5dcd29a4d8aab59e62f72df50444d2537Chris Forbes}
3107d00947f5dcd29a4d8aab59e62f72df50444d2537Chris Forbes
3108ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinskistatic bool ReportInvalidCommandBuffer(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, const char *call_source) {
3109ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski    bool skip = false;
3110ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski    for (auto obj : cb_state->broken_bindings) {
31117a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        const char *type_str = object_string[obj.type];
3112d00947f5dcd29a4d8aab59e62f72df50444d2537Chris Forbes        const char *cause_str = GetCauseStr(obj);
3113ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
31149b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(cb_state->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
3115ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                        "You are adding %s to command buffer 0x%p that is invalid because bound %s 0x%" PRIxLEAST64 " was %s.",
3116ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                        call_source, cb_state->commandBuffer, type_str, obj.handle, cause_str);
3117ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski    }
3118ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski    return skip;
3119ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski}
3120ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski
3121623784ad78c8b77a78c4db613db974c12e5f5a43Mark Lobodzinski// Validate the given command being added to the specified cmd buffer, flagging errors if CB is not in the recording state or if
3122623784ad78c8b77a78c4db613db974c12e5f5a43Mark Lobodzinski// there's an issue with the Cmd ordering
3123946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinskibool ValidateCmd(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, const CMD_TYPE cmd, const char *caller_name) {
312433f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes    switch (cb_state->state) {
312533f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes        case CB_RECORDING:
312633f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes            return ValidateCmdSubpassState(dev_data, cb_state, cmd);
312733f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes
312833f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes        case CB_INVALID:
312933f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes            return ReportInvalidCommandBuffer(dev_data, cb_state, caller_name);
313033f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes
313133f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes        default:
313233f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes            return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
31339b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                           HandleToUint64(cb_state->commandBuffer), __LINE__, DRAWSTATE_NO_BEGIN_COMMAND_BUFFER, "DS",
313433f3623e8124c3a6081b60f68b9d39a19a5840aeChris Forbes                           "You must call vkBeginCommandBuffer() before this call to %s", caller_name);
31355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
31365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
313729f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis
31381ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlisvoid UpdateCmdBufferLastCmd(GLOBAL_CB_NODE *cb_state, const CMD_TYPE cmd) {
313929f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis    if (cb_state->state == CB_RECORDING) {
314029f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        cb_state->last_cmd = cmd;
314129f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis    }
314229f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis}
31437e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis// For given object struct return a ptr of BASE_NODE type for its wrapping struct
31447e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin EhlisBASE_NODE *GetStateStructPtrFromObject(layer_data *dev_data, VK_OBJECT object_struct) {
31457e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    BASE_NODE *base_ptr = nullptr;
31467e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    switch (object_struct.type) {
3147ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeDescriptorSet: {
31489a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetSetNode(dev_data, reinterpret_cast<VkDescriptorSet &>(object_struct.handle));
3149cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3150cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3151ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeSampler: {
31529a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetSamplerState(dev_data, reinterpret_cast<VkSampler &>(object_struct.handle));
3153cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3154cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3155ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeQueryPool: {
31569a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetQueryPoolNode(dev_data, reinterpret_cast<VkQueryPool &>(object_struct.handle));
3157cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3158cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3159ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypePipeline: {
3160cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            base_ptr = getPipelineState(dev_data, reinterpret_cast<VkPipeline &>(object_struct.handle));
3161cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3162cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3163ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeBuffer: {
31649a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetBufferState(dev_data, reinterpret_cast<VkBuffer &>(object_struct.handle));
3165cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3166cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3167ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeBufferView: {
31689a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetBufferViewState(dev_data, reinterpret_cast<VkBufferView &>(object_struct.handle));
3169cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3170cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3171ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeImage: {
31729a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetImageState(dev_data, reinterpret_cast<VkImage &>(object_struct.handle));
3173cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3174cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3175ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeImageView: {
31769a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetImageViewState(dev_data, reinterpret_cast<VkImageView &>(object_struct.handle));
3177cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3178cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3179ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeEvent: {
31809a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetEventNode(dev_data, reinterpret_cast<VkEvent &>(object_struct.handle));
3181cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3182cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3183ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeDescriptorPool: {
31849a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetDescriptorPoolState(dev_data, reinterpret_cast<VkDescriptorPool &>(object_struct.handle));
3185cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3186cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3187ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeCommandPool: {
31889a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetCommandPoolNode(dev_data, reinterpret_cast<VkCommandPool &>(object_struct.handle));
3189cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3190cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3191ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeFramebuffer: {
31929a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetFramebufferState(dev_data, reinterpret_cast<VkFramebuffer &>(object_struct.handle));
3193cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3194cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3195ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeRenderPass: {
31969a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetRenderPassState(dev_data, reinterpret_cast<VkRenderPass &>(object_struct.handle));
3197cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3198cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3199ed832a346f5de647635da80bcdb95e29634c70d2Chris Forbes        case kVulkanObjectTypeDeviceMemory: {
32009a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            base_ptr = GetMemObjInfo(dev_data, reinterpret_cast<VkDeviceMemory &>(object_struct.handle));
3201cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3202cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }
3203cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        default:
3204cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            // TODO : Any other objects to be handled here?
3205cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            assert(0);
3206cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            break;
3207bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis    }
32087e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    return base_ptr;
32097e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis}
32107e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis
32117e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis// Tie the VK_OBJECT to the cmd buffer which includes:
32127e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis//  Add object_binding to cmd buffer
32137e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis//  Add cb_binding to object
32147e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlisstatic void addCommandBufferBinding(std::unordered_set<GLOBAL_CB_NODE *> *cb_bindings, VK_OBJECT obj, GLOBAL_CB_NODE *cb_node) {
32157e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    cb_bindings->insert(cb_node);
32167e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    cb_node->object_bindings.insert(obj);
32177e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis}
32187e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis// For a given object, if cb_node is in that objects cb_bindings, remove cb_node
32197e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlisstatic void removeCommandBufferBinding(layer_data *dev_data, VK_OBJECT const *object, GLOBAL_CB_NODE *cb_node) {
32207e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis    BASE_NODE *base_obj = GetStateStructPtrFromObject(dev_data, *object);
3221cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (base_obj) base_obj->cb_bindings.erase(cb_node);
3222bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis}
32235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Reset the command buffer state
32245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis//  Maintain the createInfo and set state to CB_NEW, but clear all other state
3225400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlisstatic void resetCB(layer_data *dev_data, const VkCommandBuffer cb) {
3226400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis    GLOBAL_CB_NODE *pCB = dev_data->commandBufferMap[cb];
32275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
3228b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine        pCB->in_use.store(0);
3229347d4d3139a1e743ed85bd375c20fd35bbe68d74Chris Forbes        pCB->last_cmd = CMD_NONE;
32305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Reset CB state (note that createInfo is not cleared)
32315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->commandBuffer = cb;
32325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        memset(&pCB->beginInfo, 0, sizeof(VkCommandBufferBeginInfo));
32335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        memset(&pCB->inheritanceInfo, 0, sizeof(VkCommandBufferInheritanceInfo));
3234b68b13ed4952bce61f6ebb0023542660c26b0562Chris Forbes        pCB->hasDrawCmd = false;
32355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->state = CB_NEW;
32365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->submitCount = 0;
32375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status = 0;
3238b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes        pCB->viewportMask = 0;
3239b0df98f4fa837a06691c1e3c05b4ed21c7e2d014Chris Forbes        pCB->scissorMask = 0;
324093c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski
324172d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis        for (uint32_t i = 0; i < VK_PIPELINE_BIND_POINT_RANGE_SIZE; ++i) {
324272d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis            pCB->lastBound[i].reset();
324372d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis        }
324493c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski
32455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        memset(&pCB->activeRenderPassBeginInfo, 0, sizeof(pCB->activeRenderPassBeginInfo));
3246ee691f5c5fa87aac3750454d2bca2cb582e4e817Chris Forbes        pCB->activeRenderPass = nullptr;
32475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->activeSubpassContents = VK_SUBPASS_CONTENTS_INLINE;
32485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->activeSubpass = 0;
3249e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis        pCB->broken_bindings.clear();
32505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->waitedEvents.clear();
32515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->events.clear();
3252c7e6bc41aa9c6e5a677b138b9459b252cd3bedf2Mark Lobodzinski        pCB->writeEventsBeforeWait.clear();
32535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->waitedEventsBeforeQueryReset.clear();
32545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->queryToStateMap.clear();
32555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->activeQueries.clear();
32565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->startedQueries.clear();
32575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->imageLayoutMap.clear();
32585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->eventToStageMap.clear();
32595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->drawData.clear();
32605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->currentDrawData.buffers.clear();
326158b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis        pCB->vertex_buffer_used = false;
32625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->primaryCommandBuffer = VK_NULL_HANDLE;
32631a3660584634742a3297915c94768d73f360e794Chris Forbes        // If secondary, invalidate any primary command buffer that may call us.
32641a3660584634742a3297915c94768d73f360e794Chris Forbes        if (pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY) {
32651a3660584634742a3297915c94768d73f360e794Chris Forbes            invalidateCommandBuffers(dev_data,
32661a3660584634742a3297915c94768d73f360e794Chris Forbes                                     pCB->linkedCommandBuffers,
32671a3660584634742a3297915c94768d73f360e794Chris Forbes                                     {HandleToUint64(cb), kVulkanObjectTypeCommandBuffer});
32681a3660584634742a3297915c94768d73f360e794Chris Forbes        }
32691a3660584634742a3297915c94768d73f360e794Chris Forbes
32701a3660584634742a3297915c94768d73f360e794Chris Forbes        // Remove reverse command buffer links.
32711a3660584634742a3297915c94768d73f360e794Chris Forbes        for (auto pSubCB : pCB->linkedCommandBuffers) {
32721a3660584634742a3297915c94768d73f360e794Chris Forbes            pSubCB->linkedCommandBuffers.erase(pCB);
32731a3660584634742a3297915c94768d73f360e794Chris Forbes        }
32741a3660584634742a3297915c94768d73f360e794Chris Forbes        pCB->linkedCommandBuffers.clear();
32757a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        pCB->updateImages.clear();
32767a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        pCB->updateBuffers.clear();
3277400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis        clear_cmd_buf_and_mem_references(dev_data, pCB);
3278b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        pCB->eventUpdates.clear();
3279d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        pCB->queryUpdates.clear();
328093c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski
3281bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis        // Remove object bindings
3282bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis        for (auto obj : pCB->object_bindings) {
3283bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis            removeCommandBufferBinding(dev_data, &obj, pCB);
3284bf66bca5d96f2721897c5f3100da2df741da9addTobin Ehlis        }
3285a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis        pCB->object_bindings.clear();
328693c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski        // Remove this cmdBuffer's reference from each FrameBuffer's CB ref list
328793c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski        for (auto framebuffer : pCB->framebuffers) {
32889a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto fb_state = GetFramebufferState(dev_data, framebuffer);
3289cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (fb_state) fb_state->cb_bindings.erase(pCB);
329093c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski        }
329193c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski        pCB->framebuffers.clear();
32927003b38da5cc27a063af3c45080f3a35438283eeTobin Ehlis        pCB->activeFramebuffer = VK_NULL_HANDLE;
32935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
32945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
32955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
32965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Set PSO-related status bits for CB, including dynamic state set via PSO
32974c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic void set_cb_pso_status(GLOBAL_CB_NODE *pCB, const PIPELINE_STATE *pPipe) {
32985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Account for any dynamic state not set via this PSO
3299ca546210846c65808717f8875deae39bd227c240Tobin Ehlis    if (!pPipe->graphicsPipelineCI.pDynamicState ||
3300cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        !pPipe->graphicsPipelineCI.pDynamicState->dynamicStateCount) {  // All state is static
33014052946ae557337ff95f3725e879131b1c63f865Tobin Ehlis        pCB->status |= CBSTATUS_ALL_STATE_SET;
33025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
33035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // First consider all state on
33045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Then unset any state that's noted as dynamic in PSO
33055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Finally OR that into CB statemask
33064052946ae557337ff95f3725e879131b1c63f865Tobin Ehlis        CBStatusFlags psoDynStateMask = CBSTATUS_ALL_STATE_SET;
3307ca546210846c65808717f8875deae39bd227c240Tobin Ehlis        for (uint32_t i = 0; i < pPipe->graphicsPipelineCI.pDynamicState->dynamicStateCount; i++) {
3308ca546210846c65808717f8875deae39bd227c240Tobin Ehlis            switch (pPipe->graphicsPipelineCI.pDynamicState->pDynamicStates[i]) {
3309cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_LINE_WIDTH:
3310cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_LINE_WIDTH_SET;
3311cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3312cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_DEPTH_BIAS:
3313cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_DEPTH_BIAS_SET;
3314cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3315cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_BLEND_CONSTANTS:
3316cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_BLEND_CONSTANTS_SET;
3317cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3318cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_DEPTH_BOUNDS:
3319cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_DEPTH_BOUNDS_SET;
3320cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3321cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK:
3322cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_STENCIL_READ_MASK_SET;
3323cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3324cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_STENCIL_WRITE_MASK:
3325cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_STENCIL_WRITE_MASK_SET;
3326cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3327cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                case VK_DYNAMIC_STATE_STENCIL_REFERENCE:
3328cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    psoDynStateMask &= ~CBSTATUS_STENCIL_REFERENCE_SET;
3329cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
3330cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                default:
3331cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    // TODO : Flag error here
3332cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    break;
33335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
33345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
33355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= psoDynStateMask;
33365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
33375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
33385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3339623784ad78c8b77a78c4db613db974c12e5f5a43Mark Lobodzinski// Flags validation error if the associated call is made inside a render pass. The apiName routine should ONLY be called outside a
3340623784ad78c8b77a78c4db613db974c12e5f5a43Mark Lobodzinski// render pass.
334151ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisbool insideRenderPass(const layer_data *dev_data, GLOBAL_CB_NODE *pCB, const char *apiName, UNIQUE_VALIDATION_ERROR_CODE msgCode) {
3342e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool inside = false;
33435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB->activeRenderPass) {
334451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        inside = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
33459b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                         HandleToUint64(pCB->commandBuffer), __LINE__, msgCode, "DS",
3346ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                         "%s: It is invalid to issue this call inside an active render pass (0x%" PRIxLEAST64 "). %s", apiName,
33479b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                         HandleToUint64(pCB->activeRenderPass->renderPass), validation_error_map[msgCode]);
33485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
33495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return inside;
33505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
33515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
33525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Flags validation error if the associated call is made outside a render pass. The apiName
33535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// routine should ONLY be called inside a render pass.
335451ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisbool outsideRenderPass(const layer_data *dev_data, GLOBAL_CB_NODE *pCB, const char *apiName, UNIQUE_VALIDATION_ERROR_CODE msgCode) {
3355e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool outside = false;
33565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (((pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_PRIMARY) && (!pCB->activeRenderPass)) ||
33575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        ((pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY) && (!pCB->activeRenderPass) &&
33585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis         !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT))) {
335951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis        outside = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
33609b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                          HandleToUint64(pCB->commandBuffer), __LINE__, msgCode, "DS",
3361ff97d1b78192ab7853965cd7a0462273c4813333Mike Weiblen                          "%s: This call must be issued inside an active render pass. %s", apiName, validation_error_map[msgCode]);
33625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
33635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return outside;
33645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
33655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3366f0f7d8aa2286bd7516d9fb5c2e58890505e3e5d4Chris Forbesstatic void init_core_validation(instance_layer_data *instance_data, const VkAllocationCallbacks *pAllocator) {
3367b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis    layer_debug_actions(instance_data->report_data, instance_data->logging_callback, pAllocator, "lunarg_core_validation");
33685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
33695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
33707a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis// For the given ValidationCheck enum, set all relevant instance disabled flags to true
33717a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlisvoid SetDisabledFlags(instance_layer_data *instance_data, VkValidationFlagsEXT *val_flags_struct) {
33727a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    for (uint32_t i = 0; i < val_flags_struct->disabledValidationCheckCount; ++i) {
33737a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis        switch (val_flags_struct->pDisabledValidationChecks[i]) {
337459ae0ccadec962d9ca2cce7584fad6c57c1a4458Tobin Ehlis            case VK_VALIDATION_CHECK_SHADERS_EXT:
337559ae0ccadec962d9ca2cce7584fad6c57c1a4458Tobin Ehlis                instance_data->disabled.shader_validation = true;
337659ae0ccadec962d9ca2cce7584fad6c57c1a4458Tobin Ehlis                break;
33777a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis            case VK_VALIDATION_CHECK_ALL_EXT:
33787a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis                // Set all disabled flags to true
33797a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis                instance_data->disabled.SetAll(true);
33807a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis                break;
33817a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis            default:
33827a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis                break;
33837a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis        }
33847a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    }
33857a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis}
33867a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis
3387bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
3388bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              VkInstance *pInstance) {
33895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkLayerInstanceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
33905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
33915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(chain_info->u.pLayerInfo);
33925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
33935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance");
3394cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (fpCreateInstance == NULL) return VK_ERROR_INITIALIZATION_FAILED;
33955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
33965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Advance the link info for the next element on the chain
33975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
33985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
33995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
3400cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (result != VK_SUCCESS) return result;
34015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
340256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(*pInstance), instance_layer_data_map);
340356a5ba3e60a723781945959ffc10e2e215350de5Chia-I Wu    instance_data->instance = *pInstance;
34049172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    layer_init_instance_dispatch_table(*pInstance, &instance_data->dispatch_table, fpGetInstanceProcAddr);
34059172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    instance_data->report_data = debug_report_create_instance(
34069172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes        &instance_data->dispatch_table, *pInstance, pCreateInfo->enabledExtensionCount, pCreateInfo->ppEnabledExtensionNames);
34070cf009a4e2a5c22e4645f343c7a998f188a22015Chris Forbes    instance_data->extensions.InitFromInstanceCreateInfo(pCreateInfo);
3408b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis    init_core_validation(instance_data, pAllocator);
3409825ac70f99460ccb9494d34f93d8ee7ec303e5deMark Lobodzinski
34105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    ValidateLayerOrdering(*pCreateInfo);
34117a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    // Parse any pNext chains
34127a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    if (pCreateInfo->pNext) {
34137a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis        GENERIC_HEADER *struct_header = (GENERIC_HEADER *)pCreateInfo->pNext;
34147a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis        while (struct_header) {
34157a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis            // Check for VkValidationFlagsExt
34167a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis            if (VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT == struct_header->sType) {
34177a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis                SetDisabledFlags(instance_data, (VkValidationFlagsEXT *)struct_header);
34187a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis            }
34197a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis            struct_header = (GENERIC_HEADER *)struct_header->pNext;
34207a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis        }
34217a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    }
34225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
34235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
34245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
34255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
342625002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// Hook DestroyInstance to remove tableInstanceMap entry
342789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL DestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
34285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODOSC : Shouldn't need any customization here
34295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dispatch_key key = get_dispatch_key(instance);
34305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TBD: Need any locking this early, in case this function is called at the
34315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // same time by more than one thread?
343256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(key, instance_layer_data_map);
34339172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    instance_data->dispatch_table.DestroyInstance(instance, pAllocator);
34345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3435b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::lock_guard<std::mutex> lock(global_lock);
34365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Clean up logging callback, if any
34379172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    while (instance_data->logging_callback.size() > 0) {
34389172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes        VkDebugReportCallbackEXT callback = instance_data->logging_callback.back();
34399172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes        layer_destroy_msg_callback(instance_data->report_data, callback, pAllocator);
34409172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes        instance_data->logging_callback.pop_back();
34415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
34425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
34439172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    layer_debug_report_destroy_instance(instance_data->report_data);
3444d27b109eaf4da0a5514dc2ae2f3dd6a76976ba0dGabríel Arthúr Pétursson    FreeLayerDataPtr(key, instance_layer_data_map);
34455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
34465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
34475770f8ad21c40b2475201e73e9368a899b6886d0Petr Krausstatic bool ValidatePhysicalDeviceQueueFamily(instance_layer_data *instance_data, const PHYSICAL_DEVICE_STATE *pd_state,
34485770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                              uint32_t requested_queue_family, int32_t err_code, const char *cmd_name,
34495770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                              const char *queue_family_var_name, const char *vu_note = nullptr) {
34503251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
34515770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
34525770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    if (!vu_note) vu_note = validation_error_map[err_code];
34535770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
34545770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    const char *conditional_ext_cmd =
3455d4eaca34eca7f4b4e34190c441a579347bb2016aMark Lobodzinski        instance_data->extensions.vk_khr_get_physical_device_properties_2 ? "or vkGetPhysicalDeviceQueueFamilyProperties2KHR" : "";
34565770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
34575770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    std::string count_note = (UNCALLED == pd_state->vkGetPhysicalDeviceQueueFamilyPropertiesState)
34585770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                 ? "the pQueueFamilyPropertyCount was never obtained"
34595770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                 : "i.e. is not less than " + std::to_string(pd_state->queue_family_count);
34605770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
34615770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    if (requested_queue_family >= pd_state->queue_family_count) {
34623251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
34639b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(pd_state->phys_device), __LINE__, err_code, "DL",
34649b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        "%s: %s (= %" PRIu32
34659b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        ") is not less than any previously obtained pQueueFamilyPropertyCount from "
34665770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                        "vkGetPhysicalDeviceQueueFamilyProperties%s (%s). %s",
34675770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                        cmd_name, queue_family_var_name, requested_queue_family, conditional_ext_cmd, count_note.c_str(), vu_note);
34685770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    }
34695770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    return skip;
34705770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus}
34715770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
34725770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus// Verify VkDeviceQueueCreateInfos
34735770f8ad21c40b2475201e73e9368a899b6886d0Petr Krausstatic bool ValidateDeviceQueueCreateInfos(instance_layer_data *instance_data, const PHYSICAL_DEVICE_STATE *pd_state,
34745770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                           uint32_t info_count, const VkDeviceQueueCreateInfo *infos) {
34755770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    bool skip = false;
34765770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
34775770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    for (uint32_t i = 0; i < info_count; ++i) {
34785770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        const auto requested_queue_family = infos[i].queueFamilyIndex;
34795770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
34805770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        // Verify that requested queue family is known to be valid at this point in time
34815770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        std::string queue_family_var_name = "pCreateInfo->pQueueCreateInfos[" + std::to_string(i) + "].queueFamilyIndex";
3482315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidatePhysicalDeviceQueueFamily(instance_data, pd_state, requested_queue_family, VALIDATION_ERROR_06c002fa,
34835770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                  "vkCreateDevice", queue_family_var_name.c_str());
34845770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
34855770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        // Verify that requested  queue count of queue family is known to be valid at this point in time
34865770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        if (requested_queue_family < pd_state->queue_family_count) {
34875770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus            const auto requested_queue_count = infos[i].queueCount;
34885770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus            const auto queue_family_props_count = pd_state->queue_family_properties.size();
34895770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus            const bool queue_family_has_props = requested_queue_family < queue_family_props_count;
3490d4eaca34eca7f4b4e34190c441a579347bb2016aMark Lobodzinski            const char *conditional_ext_cmd = instance_data->extensions.vk_khr_get_physical_device_properties_2
34915770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                  ? "or vkGetPhysicalDeviceQueueFamilyProperties2KHR"
34925770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                  : "";
34935770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus            std::string count_note =
34945770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                !queue_family_has_props
34955770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                    ? "the pQueueFamilyProperties[" + std::to_string(requested_queue_family) + "] was never obtained"
34965770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                    : "i.e. is not less than or equal to " +
34975770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                          std::to_string(pd_state->queue_family_properties[requested_queue_family].queueCount);
34985770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
34995770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus            if (!queue_family_has_props ||
35005770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                requested_queue_count > pd_state->queue_family_properties[requested_queue_family].queueCount) {
35013251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
35029b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, HandleToUint64(pd_state->phys_device), __LINE__,
3503315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                VALIDATION_ERROR_06c002fc, "DL",
35049b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "vkCreateDevice: pCreateInfo->pQueueCreateInfos[%" PRIu32 "].queueCount (=%" PRIu32
35059b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                ") is not "
35065770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                "less than or equal to available queue count for this "
35079b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "pCreateInfo->pQueueCreateInfos[%" PRIu32 "].queueFamilyIndex} (=%" PRIu32
35089b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                ") obtained previously "
35095770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                "from vkGetPhysicalDeviceQueueFamilyProperties%s (%s). %s",
35105770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                i, requested_queue_count, i, requested_queue_family, conditional_ext_cmd, count_note.c_str(),
3511315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                validation_error_map[VALIDATION_ERROR_06c002fc]);
3512838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski            }
3513838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski        }
3514838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski    }
35155770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
35163251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
3517838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski}
3518838e3917bc1a0479174dd753b5c28b8b2cf1954dMark Lobodzinski
3519f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski// Verify that features have been queried and that they are available
35205770f8ad21c40b2475201e73e9368a899b6886d0Petr Krausstatic bool ValidateRequestedFeatures(instance_layer_data *instance_data, const PHYSICAL_DEVICE_STATE *pd_state,
3521bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                      const VkPhysicalDeviceFeatures *requested_features) {
35223251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
3523f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
35245770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    const VkBool32 *actual = reinterpret_cast<const VkBool32 *>(&pd_state->features);
3525825ac70f99460ccb9494d34f93d8ee7ec303e5deMark Lobodzinski    const VkBool32 *requested = reinterpret_cast<const VkBool32 *>(requested_features);
3526f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    // TODO : This is a nice, compact way to loop through struct, but a bad way to report issues
3527f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    //  Need to provide the struct member name with the issue. To do that seems like we'll
3528f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    //  have to loop through each struct member which should be done w/ codegen to keep in synch.
3529f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    uint32_t errors = 0;
3530f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    uint32_t total_bools = sizeof(VkPhysicalDeviceFeatures) / sizeof(VkBool32);
3531f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    for (uint32_t i = 0; i < total_bools; i++) {
3532f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski        if (requested[i] > actual[i]) {
3533f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski            // TODO: Add index to struct member name helper to be able to include a feature name
35345770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus            skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
35355770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                            VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVLIMITS_INVALID_FEATURE_REQUESTED, "DL",
35363251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "While calling vkCreateDevice(), requesting feature #%u in VkPhysicalDeviceFeatures struct, "
35373251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "which is not available on this device.",
35383251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            i);
3539f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski            errors++;
3540f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski        }
3541f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    }
35425770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    if (errors && (UNCALLED == pd_state->vkGetPhysicalDeviceFeaturesState)) {
3543f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski        // If user didn't request features, notify them that they should
3544f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski        // TODO: Verify this against the spec. I believe this is an invalid use of the API and should return an error
35455770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
35465770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                        0, __LINE__, DEVLIMITS_INVALID_FEATURE_REQUESTED, "DL",
35473251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "You requested features that are unavailable on this device. You should first query feature "
35483251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "availability by calling vkGetPhysicalDeviceFeatures().");
3549f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    }
35503251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
3551f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski}
3552f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
355389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo,
355489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                            const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
35553251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
35565770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(gpu), instance_layer_data_map);
3557f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
35585770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    std::unique_lock<std::mutex> lock(global_lock);
3559f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    auto pd_state = GetPhysicalDeviceState(instance_data, gpu);
3560f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
3561f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    // TODO: object_tracker should perhaps do this instead
3562f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    //       and it does not seem to currently work anyway -- the loader just crashes before this point
3563f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    if (!GetPhysicalDeviceState(instance_data, gpu)) {
3564f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus        skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
3565f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                        0, __LINE__, DEVLIMITS_MUST_QUERY_COUNT, "DL",
3566f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                        "Invalid call to vkCreateDevice() w/o first calling vkEnumeratePhysicalDevices().");
3567f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    }
3568f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
3569f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    // Check that any requested features are available
3570f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    if (pCreateInfo->pEnabledFeatures) {
35715770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        skip |= ValidateRequestedFeatures(instance_data, pd_state, pCreateInfo->pEnabledFeatures);
3572f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    }
35735770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    skip |=
35745770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        ValidateDeviceQueueCreateInfos(instance_data, pd_state, pCreateInfo->queueCreateInfoCount, pCreateInfo->pQueueCreateInfos);
3575f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
35765770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
35771d659b4113b77a95325df10d602a03f1e7abf8b7Mark Mueller
35785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkLayerDeviceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
35795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
35805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    assert(chain_info->u.pLayerInfo);
35815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
35825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;
358356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(instance_data->instance, "vkCreateDevice");
35845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (fpCreateDevice == NULL) {
35855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return VK_ERROR_INITIALIZATION_FAILED;
35865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
35875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
35885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Advance the link info for the next element on the chain
35895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
35905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
35915770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    lock.unlock();
35925770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
35935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = fpCreateDevice(gpu, pCreateInfo, pAllocator, pDevice);
35945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result != VK_SUCCESS) {
35955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return result;
35965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
35975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
35985770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    lock.lock();
359956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(*pDevice), layer_data_map);
36005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
360156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    device_data->instance_data = instance_data;
36025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Setup device dispatch table
360356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_init_device_dispatch_table(*pDevice, &device_data->dispatch_table, fpGetDeviceProcAddr);
360456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    device_data->device = *pDevice;
3605ec85232c4d8d9ddf7d2ae57cb8203c5ab52c1106Mark Lobodzinski    // Save PhysicalDevice handle
360656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    device_data->physical_device = gpu;
36075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
360856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    device_data->report_data = layer_debug_report_create_device(instance_data->report_data, *pDevice);
3609a149f1a0cb39b48b19822c8cf9ef2426cd2251dfMark Lobodzinski    device_data->extensions.InitFromDeviceCreateInfo(&instance_data->extensions, pCreateInfo);
3610d4eaca34eca7f4b4e34190c441a579347bb2016aMark Lobodzinski
36115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Get physical device limits for this device
361256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceProperties(gpu, &(device_data->phys_dev_properties.properties));
36135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t count;
361456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties(gpu, &count, nullptr);
361556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    device_data->phys_dev_properties.queue_family_properties.resize(count);
361656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties(
361756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        gpu, &count, &device_data->phys_dev_properties.queue_family_properties[0]);
36185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO: device limits should make sure these are compatible
36195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCreateInfo->pEnabledFeatures) {
362056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        device_data->enabled_features = *pCreateInfo->pEnabledFeatures;
36215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
362256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        memset(&device_data->enabled_features, 0, sizeof(VkPhysicalDeviceFeatures));
36235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
3624e47dbc3f3340fa177d877a67b2adb76a570027e5Mark Lobodzinski    // Store physical device properties and physical device mem limits into device layer_data structs
362556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceMemoryProperties(gpu, &device_data->phys_dev_mem_props);
362656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceProperties(gpu, &device_data->phys_dev_props);
3627b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
36285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
36295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    ValidateLayerOrdering(*pCreateInfo);
36305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
36315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
36325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
36335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
36345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// prototype
363589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL DestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) {
36365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODOSC : Shouldn't need any customization here
36375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dispatch_key key = get_dispatch_key(device);
363856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(key, layer_data_map);
36395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Free all the memory
3640b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
36415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    deletePipelines(dev_data);
3642fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    dev_data->renderPassMap.clear();
36439b36ac77fbf55bd7ffdeb9020f2277fff3a5a807Chris Forbes    for (auto ii = dev_data->commandBufferMap.begin(); ii != dev_data->commandBufferMap.end(); ++ii) {
36449b36ac77fbf55bd7ffdeb9020f2277fff3a5a807Chris Forbes        delete (*ii).second;
36459b36ac77fbf55bd7ffdeb9020f2277fff3a5a807Chris Forbes    }
36469b36ac77fbf55bd7ffdeb9020f2277fff3a5a807Chris Forbes    dev_data->commandBufferMap.clear();
3647f13bee0887f3c3d1d597c82869864be3be836737Tobin Ehlis    // This will also delete all sets in the pool & remove them from setMap
36485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    deletePools(dev_data);
3649f13bee0887f3c3d1d597c82869864be3be836737Tobin Ehlis    // All sets should be removed
3650f13bee0887f3c3d1d597c82869864be3be836737Tobin Ehlis    assert(dev_data->setMap.empty());
3651fce842878e9ddcc7f37e1c457a4b018d52358087Tobin Ehlis    dev_data->descriptorSetLayoutMap.clear();
36525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->imageViewMap.clear();
36535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->imageMap.clear();
36545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->imageSubresourceMap.clear();
36555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->imageLayoutMap.clear();
36565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->bufferViewMap.clear();
36575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    dev_data->bufferMap.clear();
36581344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis    // Queues persist until device is destroyed
36591344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis    dev_data->queueMap.clear();
36605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Report any memory leaks
36615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    layer_debug_report_destroy_device(device);
3662b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
36635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
36645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#if DISPATCH_MAP_DEBUG
3665414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller    fprintf(stderr, "Device: 0x%p, key: 0x%p\n", device, key);
36665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis#endif
3667d27b109eaf4da0a5514dc2ae2f3dd6a76976ba0dGabríel Arthúr Pétursson
3668d27b109eaf4da0a5514dc2ae2f3dd6a76976ba0dGabríel Arthúr Pétursson    dev_data->dispatch_table.DestroyDevice(device, pAllocator);
3669d27b109eaf4da0a5514dc2ae2f3dd6a76976ba0dGabríel Arthúr Pétursson    FreeLayerDataPtr(key, layer_data_map);
36705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
36715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
36725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic const VkExtensionProperties instance_extensions[] = {{VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION}};
36735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3674208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis// For given stage mask, if Geometry shader stage is on w/o GS being enabled, report geo_error_id
3675208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis//   and if Tessellation Control or Evaluation shader stages are on w/o TS being enabled, report tess_error_id
3676208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlisstatic bool ValidateStageMaskGsTsEnables(layer_data *dev_data, VkPipelineStageFlags stageMask, const char *caller,
3677208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                                         UNIQUE_VALIDATION_ERROR_CODE geo_error_id, UNIQUE_VALIDATION_ERROR_CODE tess_error_id) {
3678208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    bool skip = false;
3679208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    if (!dev_data->enabled_features.geometryShader && (stageMask & VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT)) {
3680208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
3681cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        geo_error_id, "DL",
3682cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "%s call includes a stageMask with VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT bit set when "
3683cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "device does not have geometryShader feature enabled. %s",
3684208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                        caller, validation_error_map[geo_error_id]);
3685208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    }
3686208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    if (!dev_data->enabled_features.tessellationShader &&
3687208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        (stageMask & (VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT | VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT))) {
3688208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
3689cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        tess_error_id, "DL",
3690cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "%s call includes a stageMask with VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT "
3691cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "and/or VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT bit(s) set when device "
3692cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "does not have tessellationShader feature enabled. %s",
3693208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis                        caller, validation_error_map[tess_error_id]);
3694208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    }
3695208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    return skip;
3696208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis}
3697208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis
3698ad97d033b614e6265aaa8c8f0d21a044982d4de7Jeremy Hayes// Loop through bound objects and increment their in_use counts.
3699ad97d033b614e6265aaa8c8f0d21a044982d4de7Jeremy Hayesstatic void IncrementBoundObjects(layer_data *dev_data, GLOBAL_CB_NODE const *cb_node) {
3700a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    for (auto obj : cb_node->object_bindings) {
3701a317e7593a0fe227635fc8241908471acb36c952Chris Forbes        auto base_obj = GetStateStructPtrFromObject(dev_data, obj);
3702ad97d033b614e6265aaa8c8f0d21a044982d4de7Jeremy Hayes        if (base_obj) {
370351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            base_obj->in_use.fetch_add(1);
3704162dac96d3883e8fffaa1f988043f62c06662d2eTobin Ehlis        }
3705a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    }
3706a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis}
37075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// Track which resources are in-flight by atomically incrementing their "in_use" count
370851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic void incrementResources(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
370951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    cb_node->submitCount++;
37109a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis    cb_node->in_use.fetch_add(1);
3711a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
3712a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    // First Increment for all "generic" objects bound to cmd buffer, followed by special-case objects below
3713ad97d033b614e6265aaa8c8f0d21a044982d4de7Jeremy Hayes    IncrementBoundObjects(dev_data, cb_node);
3714a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    // TODO : We should be able to remove the NULL look-up checks from the code below as long as
3715a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    //  all the corresponding cases are verified to cause CB_INVALID state and the CB_INVALID state
3716a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    //  should then be flagged prior to calling this function
37179a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis    for (auto drawDataElement : cb_node->drawData) {
37185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto buffer : drawDataElement.buffers) {
37199a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto buffer_state = GetBufferState(dev_data, buffer);
372051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            if (buffer_state) {
37215cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis                buffer_state->in_use.fetch_add(1);
37225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
37235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
37245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
37259a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis    for (auto event : cb_node->writeEventsBeforeWait) {
37269a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto event_state = GetEventNode(dev_data, event);
3727cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (event_state) event_state->write_in_use++;
3728c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    }
37295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
37305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3731b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis// Note: This function assumes that the global lock is held by the calling thread.
3732b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis// For the given queue, verify the queue state up to the given seq number.
3733b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis// Currently the only check is to make sure that if there are events to be waited on prior to
3734b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis//  a QueryReset, make sure that all such events have been signalled.
3735d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbesstatic bool VerifyQueueStateToSeq(layer_data *dev_data, QUEUE_STATE *initial_queue, uint64_t initial_seq) {
3736b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    bool skip = false;
3737d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
3738d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes    // sequence number we want to validate up to, per queue
3739d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes    std::unordered_map<QUEUE_STATE *, uint64_t> target_seqs { { initial_queue, initial_seq } };
3740d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes    // sequence number we've completed validation for, per queue
3741d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes    std::unordered_map<QUEUE_STATE *, uint64_t> done_seqs;
3742d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes    std::vector<QUEUE_STATE *> worklist { initial_queue };
3743d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
3744d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes    while (worklist.size()) {
3745d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes        auto queue = worklist.back();
3746d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes        worklist.pop_back();
3747d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
3748d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes        auto target_seq = target_seqs[queue];
3749d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes        auto seq = std::max(done_seqs[queue], queue->seq);
3750d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes        auto sub_it = queue->submissions.begin() + int(seq - queue->seq);  // seq >= queue->seq
3751d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
3752d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes        for (; seq < target_seq; ++sub_it, ++seq) {
3753d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes            for (auto &wait : sub_it->waitSemaphores) {
3754d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                auto other_queue = GetQueueState(dev_data, wait.queue);
3755d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
3756d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                if (other_queue == queue)
3757d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                    continue;   // semaphores /always/ point backwards, so no point here.
3758d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
3759d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                auto other_target_seq = std::max(target_seqs[other_queue], wait.seq);
3760d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                auto other_done_seq = std::max(done_seqs[other_queue], other_queue->seq);
3761d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
3762d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                // if this wait is for another queue, and covers new sequence
3763d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                // numbers beyond what we've already validated, mark the new
3764d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                // target seq and (possibly-re)add the queue to the worklist.
3765d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                if (other_done_seq < other_target_seq) {
3766d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                    target_seqs[other_queue] = other_target_seq;
3767d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                    worklist.push_back(other_queue);
3768d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                }
3769d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes            }
3770d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
3771d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes            for (auto cb : sub_it->cbs) {
3772d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                auto cb_node = GetCBNode(dev_data, cb);
3773d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                if (cb_node) {
3774d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                    for (auto queryEventsPair : cb_node->waitedEventsBeforeQueryReset) {
3775d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                        for (auto event : queryEventsPair.second) {
3776d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                            if (dev_data->eventMap[event].needsSignaled) {
3777d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
3778d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                                                VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, 0, DRAWSTATE_INVALID_QUERY, "DS",
3779d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                                                "Cannot get query results on queryPool 0x%" PRIx64
3780d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                                                " with index %d which was guarded by unsignaled event 0x%" PRIx64 ".",
37819b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                                HandleToUint64(queryEventsPair.first.pool), queryEventsPair.first.index,
37829b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                                HandleToUint64(event));
3783d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes                            }
3784b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                        }
3785b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis                    }
3786b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine                }
3787b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine            }
3788b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine        }
3789d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
3790d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes        // finally mark the point we've now validated this queue to.
3791d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes        done_seqs[queue] = seq;
379292b1701c552e96e96fdbbb77e4b106a9526f3b8cTobin Ehlis    }
3793d9944715fa5a4a750a26680f08e5defe85aa7a66Chris Forbes
3794b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    return skip;
3795b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis}
3796b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis
3797b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis// When the given fence is retired, verify outstanding queue operations through the point of the fence
3798b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlisstatic bool VerifyQueueStateToFence(layer_data *dev_data, VkFence fence) {
37999a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto fence_state = GetFenceNode(dev_data, fence);
3800b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    if (VK_NULL_HANDLE != fence_state->signaler.first) {
38019a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        return VerifyQueueStateToSeq(dev_data, GetQueueState(dev_data, fence_state->signaler.first), fence_state->signaler.second);
3802b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    }
3803b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    return false;
3804b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine}
38057d33205c3aa4aba751a2c07f956634aac616f916Chris Forbes
3806a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis// Decrement in-use count for objects bound to command buffer
38072f8cbf3b166e175174877a59929902e005953d6dTobin Ehlisstatic void DecrementBoundResources(layer_data *dev_data, GLOBAL_CB_NODE const *cb_node) {
380800e8ce2e6c1c191758f7b7c15eeaf350e5b4a3b6Tobin Ehlis    BASE_NODE *base_obj = nullptr;
3809a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    for (auto obj : cb_node->object_bindings) {
38107e5c0c26004626cf6826dfe2779a738a1f9f1fffTobin Ehlis        base_obj = GetStateStructPtrFromObject(dev_data, obj);
381100e8ce2e6c1c191758f7b7c15eeaf350e5b4a3b6Tobin Ehlis        if (base_obj) {
381200e8ce2e6c1c191758f7b7c15eeaf350e5b4a3b6Tobin Ehlis            base_obj->in_use.fetch_sub(1);
381300e8ce2e6c1c191758f7b7c15eeaf350e5b4a3b6Tobin Ehlis        }
3814a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis    }
3815a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis}
3816da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes
381736c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic void RetireWorkOnQueue(layer_data *dev_data, QUEUE_STATE *pQueue, uint64_t seq) {
38189867daedbf52debc77d6568162ee21e071699b80Chris Forbes    std::unordered_map<VkQueue, uint64_t> otherQueueSeqs;
38199867daedbf52debc77d6568162ee21e071699b80Chris Forbes
38209867daedbf52debc77d6568162ee21e071699b80Chris Forbes    // Roll this queue forward, one submission at a time.
38219867daedbf52debc77d6568162ee21e071699b80Chris Forbes    while (pQueue->seq < seq) {
3822bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto &submission = pQueue->submissions.front();
38239867daedbf52debc77d6568162ee21e071699b80Chris Forbes
3824bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        for (auto &wait : submission.waitSemaphores) {
38259a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, wait.semaphore);
3826c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            if (pSemaphore) {
3827c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski                pSemaphore->in_use.fetch_sub(1);
3828c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            }
3829bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            auto &lastSeq = otherQueueSeqs[wait.queue];
38309867daedbf52debc77d6568162ee21e071699b80Chris Forbes            lastSeq = std::max(lastSeq, wait.seq);
3831da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes        }
3832cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes
3833bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        for (auto &semaphore : submission.signalSemaphores) {
38349a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
3835c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            if (pSemaphore) {
3836c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski                pSemaphore->in_use.fetch_sub(1);
3837c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            }
38389867daedbf52debc77d6568162ee21e071699b80Chris Forbes        }
3839cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes
38409867daedbf52debc77d6568162ee21e071699b80Chris Forbes        for (auto cb : submission.cbs) {
38419a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto cb_node = GetCBNode(dev_data, cb);
3842c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            if (!cb_node) {
3843c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski                continue;
3844c91c376e7f18eba22f2996e514eb4714417fb343Mark Lobodzinski            }
3845a45bdcb94b2fbda36bc191e12cc20218f62fb0e0Tobin Ehlis            // First perform decrement on general case bound objects
38469a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            DecrementBoundResources(dev_data, cb_node);
38479a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            for (auto drawDataElement : cb_node->drawData) {
38489867daedbf52debc77d6568162ee21e071699b80Chris Forbes                for (auto buffer : drawDataElement.buffers) {
38499a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto buffer_state = GetBufferState(dev_data, buffer);
38505cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis                    if (buffer_state) {
38515cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis                        buffer_state->in_use.fetch_sub(1);
38529867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    }
38539867daedbf52debc77d6568162ee21e071699b80Chris Forbes                }
3854da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes            }
38559a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            for (auto event : cb_node->writeEventsBeforeWait) {
38569867daedbf52debc77d6568162ee21e071699b80Chris Forbes                auto eventNode = dev_data->eventMap.find(event);
38579867daedbf52debc77d6568162ee21e071699b80Chris Forbes                if (eventNode != dev_data->eventMap.end()) {
38589867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    eventNode->second.write_in_use--;
38599867daedbf52debc77d6568162ee21e071699b80Chris Forbes                }
38609867daedbf52debc77d6568162ee21e071699b80Chris Forbes            }
38619a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            for (auto queryStatePair : cb_node->queryToStateMap) {
38629867daedbf52debc77d6568162ee21e071699b80Chris Forbes                dev_data->queryToStateMap[queryStatePair.first] = queryStatePair.second;
38639867daedbf52debc77d6568162ee21e071699b80Chris Forbes            }
38649a61300d900fe3e43e9a03c7fa6876934bc1264eTobin Ehlis            for (auto eventStagePair : cb_node->eventToStageMap) {
38659867daedbf52debc77d6568162ee21e071699b80Chris Forbes                dev_data->eventMap[eventStagePair.first].stageMask = eventStagePair.second;
3866da8f07baf262972eb3e719fa07b073c180dff157Chris Forbes            }
38670a32ed7bdf03e7bda914e03c0bfa6ebf400cdf5bMichael Lentine
3868a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes            cb_node->in_use.fetch_sub(1);
38690a32ed7bdf03e7bda914e03c0bfa6ebf400cdf5bMichael Lentine        }
38709867daedbf52debc77d6568162ee21e071699b80Chris Forbes
38719a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto pFence = GetFenceNode(dev_data, submission.fence);
38729867daedbf52debc77d6568162ee21e071699b80Chris Forbes        if (pFence) {
38739867daedbf52debc77d6568162ee21e071699b80Chris Forbes            pFence->state = FENCE_RETIRED;
38740a32ed7bdf03e7bda914e03c0bfa6ebf400cdf5bMichael Lentine        }
38759867daedbf52debc77d6568162ee21e071699b80Chris Forbes
38769867daedbf52debc77d6568162ee21e071699b80Chris Forbes        pQueue->submissions.pop_front();
38779867daedbf52debc77d6568162ee21e071699b80Chris Forbes        pQueue->seq++;
3878b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
38799867daedbf52debc77d6568162ee21e071699b80Chris Forbes
38809867daedbf52debc77d6568162ee21e071699b80Chris Forbes    // Roll other queues forward to the highest seq we saw a wait for
38819867daedbf52debc77d6568162ee21e071699b80Chris Forbes    for (auto qs : otherQueueSeqs) {
38829a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        RetireWorkOnQueue(dev_data, GetQueueState(dev_data, qs.first), qs.second);
3883d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    }
38849867daedbf52debc77d6568162ee21e071699b80Chris Forbes}
3885651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
3886651d92815dfff917308137bb67aacccc4f60df86Chris Forbes// Submit a fence to a queue, delimiting previous fences and previous untracked
3887651d92815dfff917308137bb67aacccc4f60df86Chris Forbes// work by it.
388836c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic void SubmitFence(QUEUE_STATE *pQueue, FENCE_NODE *pFence, uint64_t submitCount) {
3889cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes    pFence->state = FENCE_INFLIGHT;
38909867daedbf52debc77d6568162ee21e071699b80Chris Forbes    pFence->signaler.first = pQueue->queue;
38919867daedbf52debc77d6568162ee21e071699b80Chris Forbes    pFence->signaler.second = pQueue->seq + pQueue->submissions.size() + submitCount;
3892b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine}
3893b3d308d63ba34f40839f009ac83b33962d7f26b2Michael Lentine
389451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic bool validateCommandBufferSimultaneousUse(layer_data *dev_data, GLOBAL_CB_NODE *pCB, int current_submit_count) {
38953251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
3896a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes    if ((pCB->in_use.load() || current_submit_count > 1) &&
38975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
38983251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
3899315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        __LINE__, VALIDATION_ERROR_31a0008e, "DS",
39003251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Command Buffer 0x%p is already in use and is not marked for simultaneous use. %s", pCB->commandBuffer,
3901315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_31a0008e]);
39025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
39033251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
39045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
39055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
3906946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinskistatic bool validateCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, const char *call_source,
39070de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                                       int current_submit_count, UNIQUE_VALIDATION_ERROR_CODE vu_id) {
3908c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis    bool skip = false;
3909cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.command_buffer_state) return skip;
39100a59acde4b40fde3bbfea5811d2abf2c85ca62f4Tobin Ehlis    // Validate ONE_TIME_SUBMIT_BIT CB is not being submitted more than once
3911946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if ((cb_state->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) &&
3912946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        (cb_state->submitCount + current_submit_count > 1)) {
3913c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
3914c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis                        __LINE__, DRAWSTATE_COMMAND_BUFFER_SINGLE_SUBMIT_VIOLATION, "DS",
3915226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "Commandbuffer 0x%p was begun w/ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT "
3916c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis                        "set, but has been submitted 0x%" PRIxLEAST64 " times.",
3917946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        cb_state->commandBuffer, cb_state->submitCount + current_submit_count);
39180a59acde4b40fde3bbfea5811d2abf2c85ca62f4Tobin Ehlis    }
391994307efee520ad91d5da2ff8f40609b31f05b2efChris Forbes
39205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Validate that cmd buffers have been updated
3921946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (CB_RECORDED != cb_state->state) {
3922946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        if (CB_INVALID == cb_state->state) {
3923946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            skip |= ReportInvalidCommandBuffer(dev_data, cb_state, call_source);
39240de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski        } else if (CB_NEW == cb_state->state) {
39250de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
39260de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            (uint64_t)(cb_state->commandBuffer), __LINE__, vu_id, "DS",
39270de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            "Command buffer 0x%p used in the call to %s is unrecorded and contains no commands. %s",
39280de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            cb_state->commandBuffer, call_source, validation_error_map[vu_id]);
3929cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        } else {  // Flag error for using CB w/o vkEndCommandBuffer() called
3930c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
39319b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(cb_state->commandBuffer), __LINE__, DRAWSTATE_NO_END_COMMAND_BUFFER, "DS",
3932946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            "You must call vkEndCommandBuffer() on command buffer 0x%p before this call to %s!",
3933946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            cb_state->commandBuffer, call_source);
39345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
39355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
3936c264142df95edb7eb96b5dc2d87562efce6ded43Tobin Ehlis    return skip;
39375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
39385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
393951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic bool validateResources(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
39403251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
394151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
394251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    // TODO : We should be able to remove the NULL look-up checks from the code below as long as
394351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    //  all the corresponding cases are verified to cause CB_INVALID state and the CB_INVALID state
394451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    //  should then be flagged prior to calling this function
394551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    for (auto drawDataElement : cb_node->drawData) {
394651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        for (auto buffer : drawDataElement.buffers) {
394751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            auto buffer_state = GetBufferState(dev_data, buffer);
394851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            if (!buffer_state) {
39493251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
39509b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(buffer), __LINE__, DRAWSTATE_INVALID_BUFFER, "DS",
39519b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "Cannot submit cmd buffer using deleted buffer 0x%" PRIx64 ".", HandleToUint64(buffer));
395251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            }
395351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        }
395451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    }
39553251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
395651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour}
395751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
3958f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski// Check that the queue family index of 'queue' matches one of the entries in pQueueFamilyIndices
3959f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinskibool ValidImageBufferQueue(layer_data *dev_data, GLOBAL_CB_NODE *cb_node, const VK_OBJECT *object, VkQueue queue, uint32_t count,
3960f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                           const uint32_t *indices) {
3961f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski    bool found = false;
3962f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski    bool skip = false;
3963f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski    auto queue_state = GetQueueState(dev_data, queue);
3964f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski    if (queue_state) {
3965f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        for (uint32_t i = 0; i < count; i++) {
3966f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski            if (indices[i] == queue_state->queueFamilyIndex) {
3967f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                found = true;
3968f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                break;
3969f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski            }
3970f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        }
3971f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski
3972f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        if (!found) {
39739b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus            skip = log_msg(
39749b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, get_debug_report_enum[object->type], object->handle, __LINE__,
39759b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                DRAWSTATE_INVALID_QUEUE_FAMILY, "DS", "vkQueueSubmit: Command buffer 0x%" PRIxLEAST64 " contains %s 0x%" PRIxLEAST64
39769b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                                      " which was not created allowing concurrent access to this queue family %d.",
39779b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                HandleToUint64(cb_node->commandBuffer), object_string[object->type], object->handle, queue_state->queueFamilyIndex);
3978f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        }
3979f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski    }
3980f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski    return skip;
3981f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski}
3982f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski
39837bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski// Validate that queueFamilyIndices of primary command buffers match this queue
39847bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski// Secondary command buffers were previously validated in vkCmdExecuteCommands().
39857bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinskistatic bool validateQueueFamilyIndices(layer_data *dev_data, GLOBAL_CB_NODE *pCB, VkQueue queue) {
39863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
39879a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pPool = GetCommandPoolNode(dev_data, pCB->createInfo.commandPool);
39889a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto queue_state = GetQueueState(dev_data, queue);
39897bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
3990f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski    if (pPool && queue_state) {
3991f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        if (pPool->queueFamilyIndex != queue_state->queueFamilyIndex) {
39923251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3993315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(pCB->commandBuffer), __LINE__, VALIDATION_ERROR_31a00094, "DS",
39943251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkQueueSubmit: Primary command buffer 0x%p created in queue family %d is being submitted on queue "
39953251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "0x%p from queue family %d. %s",
39963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            pCB->commandBuffer, pPool->queueFamilyIndex, queue, queue_state->queueFamilyIndex,
3997315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_31a00094]);
3998f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        }
3999f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski
4000f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        // Ensure that any bound images or buffers created with SHARING_MODE_CONCURRENT have access to the current queue family
4001f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        for (auto object : pCB->object_bindings) {
40027a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski            if (object.type == kVulkanObjectTypeImage) {
4003f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                auto image_state = GetImageState(dev_data, reinterpret_cast<VkImage &>(object.handle));
4004f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                if (image_state && image_state->createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) {
40053251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= ValidImageBufferQueue(dev_data, pCB, &object, queue, image_state->createInfo.queueFamilyIndexCount,
40063251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                  image_state->createInfo.pQueueFamilyIndices);
4007f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                }
40087a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski            } else if (object.type == kVulkanObjectTypeBuffer) {
4009f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                auto buffer_state = GetBufferState(dev_data, reinterpret_cast<VkBuffer &>(object.handle));
4010f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                if (buffer_state && buffer_state->createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) {
40113251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= ValidImageBufferQueue(dev_data, pCB, &object, queue, buffer_state->createInfo.queueFamilyIndexCount,
40123251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                  buffer_state->createInfo.pQueueFamilyIndices);
4013f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski                }
4014f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski            }
4015f26f0f4b1c6b014d9abc2414a9ed255ecade9f04Mark Lobodzinski        }
40167bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski    }
40177bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
40183251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
40197bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski}
40207bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
402151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic bool validatePrimaryCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB, int current_submit_count) {
40225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Track in-use for resources off of primary and any secondary CBs
40233251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
4024a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
4025a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes    // If USAGE_SIMULTANEOUS_USE_BIT not set then CB cannot already be executing
4026a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes    // on device
40273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= validateCommandBufferSimultaneousUse(dev_data, pCB, current_submit_count);
4028a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
40293251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= validateResources(dev_data, pCB);
4030a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
40311a3660584634742a3297915c94768d73f360e794Chris Forbes    for (auto pSubCB : pCB->linkedCommandBuffers) {
403211decd82041d4b10aac41360fc76b6fda4f4bd27Chris Forbes        skip |= validateResources(dev_data, pSubCB);
40331a3660584634742a3297915c94768d73f360e794Chris Forbes        // TODO: replace with invalidateCommandBuffers() at recording.
403411decd82041d4b10aac41360fc76b6fda4f4bd27Chris Forbes        if ((pSubCB->primaryCommandBuffer != pCB->commandBuffer) &&
403511decd82041d4b10aac41360fc76b6fda4f4bd27Chris Forbes            !(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
4036315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
4037315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                    __LINE__, VALIDATION_ERROR_31a00092, "DS",
4038315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                    "Commandbuffer 0x%p was submitted with secondary buffer 0x%p but that buffer has subsequently been bound to "
4039f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                    "primary cmd buffer 0x%p and it does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set. %s",
4040315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                    pCB->commandBuffer, pSubCB->commandBuffer, pSubCB->primaryCommandBuffer,
4041315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                    validation_error_map[VALIDATION_ERROR_31a00092]);
40425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
40435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
4044a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
4045315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= validateCommandBufferState(dev_data, pCB, "vkQueueSubmit()", current_submit_count, VALIDATION_ERROR_31a00090);
4046a2d08a743ac1178e4d46da4d41c73fb73b5e79d7Chris Forbes
40473251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
40485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
40495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4050bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool ValidateFenceForSubmit(layer_data *dev_data, FENCE_NODE *pFence) {
40513251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
405281c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes
4053651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    if (pFence) {
4054cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes        if (pFence->state == FENCE_INFLIGHT) {
4055315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            // TODO: opportunities for VALIDATION_ERROR_31a00080, VALIDATION_ERROR_316008b4, VALIDATION_ERROR_16400a0e
40563251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
40579b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pFence->fence), __LINE__, DRAWSTATE_INVALID_FENCE, "DS",
40589b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "Fence 0x%" PRIx64 " is already in use by another submission.", HandleToUint64(pFence->fence));
4059a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        }
406081c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes
4061cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes        else if (pFence->state == FENCE_RETIRED) {
4062315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            // TODO: opportunities for VALIDATION_ERROR_31a0007e, VALIDATION_ERROR_316008b2, VALIDATION_ERROR_16400a0e
40633251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
40649b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pFence->fence), __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM",
40653251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Fence 0x%" PRIxLEAST64 " submitted in SIGNALED state.  Fences must be reset before being submitted",
40669b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pFence->fence));
4067a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        }
40685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
406981c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes
40703251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
407181c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes}
407281c4a32a622486043c15e427fb0e85cc1cf7dd47Chris Forbes
407351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic void PostCallRecordQueueSubmit(layer_data *dev_data, VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits,
407451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                                      VkFence fence) {
40759a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pQueue = GetQueueState(dev_data, queue);
40769a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pFence = GetFenceNode(dev_data, fence);
4077d7d60cccc862fee2d0b3ad410c5fdcc40ddc83aeChris Forbes
4078651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    // Mark the fence in-use.
4079651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    if (pFence) {
40809867daedbf52debc77d6568162ee21e071699b80Chris Forbes        SubmitFence(pQueue, pFence, std::max(1u, submitCount));
4081651d92815dfff917308137bb67aacccc4f60df86Chris Forbes    }
4082651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
408351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    // Now process each individual submit
40845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
408551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        std::vector<VkCommandBuffer> cbs;
40865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubmitInfo *submit = &pSubmits[submit_idx];
40879867daedbf52debc77d6568162ee21e071699b80Chris Forbes        vector<SEMAPHORE_WAIT> semaphore_waits;
40889867daedbf52debc77d6568162ee21e071699b80Chris Forbes        vector<VkSemaphore> semaphore_signals;
40895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < submit->waitSemaphoreCount; ++i) {
409051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            VkSemaphore semaphore = submit->pWaitSemaphores[i];
409151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
409251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            if (pSemaphore) {
409351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                if (pSemaphore->signaler.first != VK_NULL_HANDLE) {
409451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    semaphore_waits.push_back({semaphore, pSemaphore->signaler.first, pSemaphore->signaler.second});
409551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    pSemaphore->in_use.fetch_add(1);
409651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                }
409751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->signaler.first = VK_NULL_HANDLE;
409851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->signaled = false;
409951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            }
410051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        }
410151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        for (uint32_t i = 0; i < submit->signalSemaphoreCount; ++i) {
410251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            VkSemaphore semaphore = submit->pSignalSemaphores[i];
410351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
410451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            if (pSemaphore) {
410551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->signaler.first = queue;
410651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->signaler.second = pQueue->seq + pQueue->submissions.size() + 1;
410751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->signaled = true;
410851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                pSemaphore->in_use.fetch_add(1);
410951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                semaphore_signals.push_back(semaphore);
411051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            }
411151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        }
411251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        for (uint32_t i = 0; i < submit->commandBufferCount; i++) {
411351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            auto cb_node = GetCBNode(dev_data, submit->pCommandBuffers[i]);
411451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            if (cb_node) {
411551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                cbs.push_back(submit->pCommandBuffers[i]);
41161a3660584634742a3297915c94768d73f360e794Chris Forbes                for (auto secondaryCmdBuffer : cb_node->linkedCommandBuffers) {
411711decd82041d4b10aac41360fc76b6fda4f4bd27Chris Forbes                    cbs.push_back(secondaryCmdBuffer->commandBuffer);
411851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                }
411951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                UpdateCmdBufImageLayouts(dev_data, cb_node);
412051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                incrementResources(dev_data, cb_node);
41211a3660584634742a3297915c94768d73f360e794Chris Forbes                for (auto secondaryCmdBuffer : cb_node->linkedCommandBuffers) {
412211decd82041d4b10aac41360fc76b6fda4f4bd27Chris Forbes                    incrementResources(dev_data, secondaryCmdBuffer);
412351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                }
412451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour            }
412551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        }
412651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        pQueue->submissions.emplace_back(cbs, semaphore_waits, semaphore_signals,
412751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                                         submit_idx == submitCount - 1 ? fence : VK_NULL_HANDLE);
412851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    }
412951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
413051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    if (pFence && !submitCount) {
413151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        // If no submissions, but just dropping a fence on the end of the queue,
413251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        // record an empty submission with just the fence, so we can determine
413351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        // its completion.
413451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        pQueue->submissions.emplace_back(std::vector<VkCommandBuffer>(), std::vector<SEMAPHORE_WAIT>(), std::vector<VkSemaphore>(),
413551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                                         fence);
413651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    }
413751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour}
413851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
413951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbourstatic bool PreCallValidateQueueSubmit(layer_data *dev_data, VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits,
414051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                                       VkFence fence) {
414151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    auto pFence = GetFenceNode(dev_data, fence);
41423251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = ValidateFenceForSubmit(dev_data, pFence);
41433251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) {
414451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        return true;
414551920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    }
414651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
414751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    unordered_set<VkSemaphore> signaled_semaphores;
414851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    unordered_set<VkSemaphore> unsignaled_semaphores;
414951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    vector<VkCommandBuffer> current_cmds;
415051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> localImageLayoutMap = dev_data->imageLayoutMap;
415151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    // Now verify each individual submit
415251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
415351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        const VkSubmitInfo *submit = &pSubmits[submit_idx];
415451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour        for (uint32_t i = 0; i < submit->waitSemaphoreCount; ++i) {
4155315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            skip |= ValidateStageMaskGsTsEnables(dev_data, submit->pWaitDstStageMask[i], "vkQueueSubmit()",
4156315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                 VALIDATION_ERROR_13c00098, VALIDATION_ERROR_13c0009a);
415701a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            VkSemaphore semaphore = submit->pWaitSemaphores[i];
41589a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
415901a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            if (pSemaphore) {
416051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                if (unsignaled_semaphores.count(semaphore) ||
4161440bdd357701497c3442e3515f12ac1cfffc180aTony Barbour                    (!(signaled_semaphores.count(semaphore)) && !(pSemaphore->signaled))) {
41623251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
41639b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    HandleToUint64(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
41643251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "Queue 0x%p is waiting on semaphore 0x%" PRIx64 " that has no way to be signaled.", queue,
41659b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    HandleToUint64(semaphore));
416651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                } else {
416751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    signaled_semaphores.erase(semaphore);
416851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    unsignaled_semaphores.insert(semaphore);
41691344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                }
41705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
41715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
41725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < submit->signalSemaphoreCount; ++i) {
417301a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            VkSemaphore semaphore = submit->pSignalSemaphores[i];
41749a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
417501a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            if (pSemaphore) {
4176440bdd357701497c3442e3515f12ac1cfffc180aTony Barbour                if (signaled_semaphores.count(semaphore) || (!(unsignaled_semaphores.count(semaphore)) && pSemaphore->signaled)) {
41773251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
41789b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    HandleToUint64(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
41793251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "Queue 0x%p is signaling semaphore 0x%" PRIx64
41803251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    " that has already been signaled but not waited on by queue 0x%" PRIx64 ".",
41819b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    queue, HandleToUint64(semaphore), HandleToUint64(pSemaphore->signaler.first));
41821344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                } else {
418351920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    unsignaled_semaphores.erase(semaphore);
418451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    signaled_semaphores.insert(semaphore);
41851344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                }
41860a32ed7bdf03e7bda914e03c0bfa6ebf400cdf5bMichael Lentine            }
41875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
41885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < submit->commandBufferCount; i++) {
41899a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto cb_node = GetCBNode(dev_data, submit->pCommandBuffers[i]);
4190d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis            if (cb_node) {
41913251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= ValidateCmdBufImageLayouts(dev_data, cb_node, localImageLayoutMap);
419251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                current_cmds.push_back(submit->pCommandBuffers[i]);
41933251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= validatePrimaryCommandBufferState(
419451920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    dev_data, cb_node, (int)std::count(current_cmds.begin(), current_cmds.end(), submit->pCommandBuffers[i]));
41953251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= validateQueueFamilyIndices(dev_data, cb_node, queue);
419651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
4197ea371fa7c8c57edb4d1436e4570cf54f3fc0463fTobin Ehlis                // Potential early exit here as bad object state may crash in delayed function calls
41983251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                if (skip) {
419951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                    return true;
420051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour                }
420151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
42021344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                // Call submit-time functions to validate/update state
4203d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                for (auto &function : cb_node->validate_functions) {
42043251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= function();
42051344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                }
4206d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                for (auto &function : cb_node->eventUpdates) {
42073251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= function(queue);
42081344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                }
4209d74f8771414d9e80618cd7604ea4b1c459dfa42eTobin Ehlis                for (auto &function : cb_node->queryUpdates) {
42103251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= function(queue);
4211d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                }
42121344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis            }
42135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
42149867daedbf52debc77d6568162ee21e071699b80Chris Forbes    }
42153251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
421651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour}
42179867daedbf52debc77d6568162ee21e071699b80Chris Forbes
421851920949f887ce8d3666c73c28ff19a5d8325a37Tony BarbourVKAPI_ATTR VkResult VKAPI_CALL QueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence) {
421951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
422051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    std::unique_lock<std::mutex> lock(global_lock);
422151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
422251920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    bool skip = PreCallValidateQueueSubmit(dev_data, queue, submitCount, pSubmits, fence);
4223b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
42245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4225440bdd357701497c3442e3515f12ac1cfffc180aTony Barbour    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
422651920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
422751920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    VkResult result = dev_data->dispatch_table.QueueSubmit(queue, submitCount, pSubmits, fence);
422851920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour
422951920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    lock.lock();
423051920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    PostCallRecordQueueSubmit(dev_data, queue, submitCount, pSubmits, fence);
423151920949f887ce8d3666c73c28ff19a5d8325a37Tony Barbour    lock.unlock();
42325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
42335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
42345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4235f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultzstatic bool PreCallValidateAllocateMemory(layer_data *dev_data) {
4236f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    bool skip = false;
4237f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    if (dev_data->memObjMap.size() >= dev_data->phys_dev_properties.properties.limits.maxMemoryAllocationCount) {
4238f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
4239315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_16c004f8, "MEM",
4240f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz                        "Number of currently valid memory objects is not less than the maximum allowed (%u). %s",
4241f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz                        dev_data->phys_dev_properties.properties.limits.maxMemoryAllocationCount,
4242315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_16c004f8]);
4243f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    }
4244f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    return skip;
4245f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz}
4246f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz
4247f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultzstatic void PostCallRecordAllocateMemory(layer_data *dev_data, const VkMemoryAllocateInfo *pAllocateInfo, VkDeviceMemory *pMemory) {
4248f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    add_mem_obj_info(dev_data, dev_data->device, *pMemory, pAllocateInfo);
4249f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    return;
4250f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz}
4251f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz
425289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL AllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo,
425389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                              const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory) {
4254f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
425556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
4256f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    std::unique_lock<std::mutex> lock(global_lock);
4257f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    bool skip = PreCallValidateAllocateMemory(dev_data);
4258f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz    if (!skip) {
4259f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        lock.unlock();
4260f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        result = dev_data->dispatch_table.AllocateMemory(device, pAllocateInfo, pAllocator, pMemory);
4261f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        lock.lock();
4262f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        if (VK_SUCCESS == result) {
4263f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz            PostCallRecordAllocateMemory(dev_data, pAllocateInfo, pMemory);
4264f9e31fcaf5f4630e1bf38870a6457e1a04b4a486Karl Schultz        }
4265e12739a56d02ca2fb5f0273862668e7475a21a6cMark Lobodzinski    }
42665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
42675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
42685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4269177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis// For given obj node, if it is use, flag a validation error and return callback result, else return false
4270177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlisbool ValidateObjectNotInUse(const layer_data *dev_data, BASE_NODE *obj_node, VK_OBJECT obj_struct,
4271177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis                            UNIQUE_VALIDATION_ERROR_CODE error_code) {
4272cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.object_in_use) return false;
4273177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    bool skip = false;
4274177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    if (obj_node->in_use.load()) {
42757a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        skip |=
427602a510945ff39f3d9e486e456aca5bfa6ea0c43aMark Lobodzinski            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, get_debug_report_enum[obj_struct.type], obj_struct.handle,
42777a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski                    __LINE__, error_code, "DS", "Cannot delete %s 0x%" PRIx64 " that is currently in use by a command buffer. %s",
42787a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski                    object_string[obj_struct.type], obj_struct.handle, validation_error_map[error_code]);
4279177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    }
4280177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    return skip;
4281177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis}
42825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4283177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlisstatic bool PreCallValidateFreeMemory(layer_data *dev_data, VkDeviceMemory mem, DEVICE_MEM_INFO **mem_info, VK_OBJECT *obj_struct) {
42849a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *mem_info = GetMemObjInfo(dev_data, mem);
42859b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    *obj_struct = {HandleToUint64(mem), kVulkanObjectTypeDeviceMemory};
4286cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.free_memory) return false;
4287177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    bool skip = false;
4288177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    if (*mem_info) {
4289315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *mem_info, *obj_struct, VALIDATION_ERROR_2880054a);
4290177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    }
4291177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    return skip;
4292177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis}
42935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4294177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlisstatic void PostCallRecordFreeMemory(layer_data *dev_data, VkDeviceMemory mem, DEVICE_MEM_INFO *mem_info, VK_OBJECT obj_struct) {
4295177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    // Clear mem binding for any bound objects
429647705d01140c9f1492885e6efc5fa262e7e1c6a0Tobin Ehlis    for (auto obj : mem_info->obj_bindings) {
429702a510945ff39f3d9e486e456aca5bfa6ea0c43aMark Lobodzinski        log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, get_debug_report_enum[obj.type], obj.handle, __LINE__,
42987a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski                MEMTRACK_FREED_MEM_REF, "MEM", "VK Object 0x%" PRIxLEAST64 " still has a reference to mem obj 0x%" PRIxLEAST64,
42999b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                obj.handle, HandleToUint64(mem_info->mem));
430047705d01140c9f1492885e6efc5fa262e7e1c6a0Tobin Ehlis        switch (obj.type) {
43017a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski            case kVulkanObjectTypeImage: {
43029a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto image_state = GetImageState(dev_data, reinterpret_cast<VkImage &>(obj.handle));
4303cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                assert(image_state);  // Any destroyed images should already be removed from bindings
4304cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                image_state->binding.mem = MEMORY_UNBOUND;
4305cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4306cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
43077a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski            case kVulkanObjectTypeBuffer: {
43089a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto buffer_state = GetBufferState(dev_data, reinterpret_cast<VkBuffer &>(obj.handle));
4309cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                assert(buffer_state);  // Any destroyed buffers should already be removed from bindings
4310cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                buffer_state->binding.mem = MEMORY_UNBOUND;
4311cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
4312cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            }
4313cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
4314cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // Should only have buffer or image objects bound to memory
4315cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                assert(0);
4316177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        }
4317177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    }
4318177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    // Any bound cmd buffers are now invalid
431939c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, mem_info->cb_bindings, obj_struct);
4320177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    dev_data->memObjMap.erase(mem);
4321177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis}
4322177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis
4323177063aac84fac6f4e650c2629a08b48be643f96Tobin EhlisVKAPI_ATTR void VKAPI_CALL FreeMemory(VkDevice device, VkDeviceMemory mem, const VkAllocationCallbacks *pAllocator) {
432456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
4325177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    DEVICE_MEM_INFO *mem_info = nullptr;
4326177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    VK_OBJECT obj_struct;
4327b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
4328177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    bool skip = PreCallValidateFreeMemory(dev_data, mem, &mem_info, &obj_struct);
4329177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis    if (!skip) {
4330177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        lock.unlock();
4331177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        dev_data->dispatch_table.FreeMemory(device, mem, pAllocator);
4332177063aac84fac6f4e650c2629a08b48be643f96Tobin Ehlis        lock.lock();
4333405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (mem != VK_NULL_HANDLE) {
4334405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordFreeMemory(dev_data, mem, mem_info, obj_struct);
4335405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
433674243a735fe102b370237ddf80d3e6f7ec5246dbMark Mueller    }
43375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
43385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4339f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis// Validate that given Map memory range is valid. This means that the memory should not already be mapped,
4340f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis//  and that the size of the map range should be:
4341f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis//  1. Not zero
4342f57fc64ac43691ad98e1713886b345465573070aTobin Ehlis//  2. Within the size of the memory allocation
434351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool ValidateMapMemRange(layer_data *dev_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size) {
43443251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
43455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
43465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (size == 0) {
43473251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
43489b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       HandleToUint64(mem), __LINE__, MEMTRACK_INVALID_MAP, "MEM",
43493251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                       "VkMapMemory: Attempting to map memory range of size zero");
43505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
43515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
435251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    auto mem_element = dev_data->memObjMap.find(mem);
435351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    if (mem_element != dev_data->memObjMap.end()) {
435457fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        auto mem_info = mem_element->second.get();
43555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // It is an application error to call VkMapMemory on an object that is already mapped
4356de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        if (mem_info->mem_range.size != 0) {
43579b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus            skip =
43589b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
43599b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(mem), __LINE__, MEMTRACK_INVALID_MAP, "MEM",
43609b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        "VkMapMemory: Attempting to map memory on an already-mapped object 0x%" PRIxLEAST64, HandleToUint64(mem));
43615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
43625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
43635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Validate that offset + size is within object's allocationSize
43645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (size == VK_WHOLE_SIZE) {
4365de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis            if (offset >= mem_info->alloc_info.allocationSize) {
43663251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
43679b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                               HandleToUint64(mem), __LINE__, MEMTRACK_INVALID_MAP, "MEM",
43683251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                               "Mapping Memory from 0x%" PRIx64 " to 0x%" PRIx64
43693251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                               " with size of VK_WHOLE_SIZE oversteps total array size 0x%" PRIx64,
43703251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                               offset, mem_info->alloc_info.allocationSize, mem_info->alloc_info.allocationSize);
43715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
43725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
4373de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis            if ((offset + size) > mem_info->alloc_info.allocationSize) {
43743251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
4375315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                               HandleToUint64(mem), __LINE__, VALIDATION_ERROR_31200552, "MEM",
43763251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                               "Mapping Memory from 0x%" PRIx64 " to 0x%" PRIx64 " oversteps total array size 0x%" PRIx64 ". %s",
43773251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                               offset, size + offset, mem_info->alloc_info.allocationSize,
4378315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                               validation_error_map[VALIDATION_ERROR_31200552]);
43795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
43805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
43815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
43823251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
43835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
43845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
438551ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic void storeMemRanges(layer_data *dev_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size) {
43869a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto mem_info = GetMemObjInfo(dev_data, mem);
438757fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    if (mem_info) {
4388de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        mem_info->mem_range.offset = offset;
4389de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        mem_info->mem_range.size = size;
43905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
43915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
43925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
439351ea774638f432bd8e700ec8291a980f405f429eTobin Ehlisstatic bool deleteMemRanges(layer_data *dev_data, VkDeviceMemory mem) {
43943251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
43959a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto mem_info = GetMemObjInfo(dev_data, mem);
439657fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    if (mem_info) {
4397de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        if (!mem_info->mem_range.size) {
43985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Valid Usage: memory must currently be mapped
43993251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
4400315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                           HandleToUint64(mem), __LINE__, VALIDATION_ERROR_33600562, "MEM",
44019b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                           "Unmapping Memory without memory being mapped: mem obj 0x%" PRIxLEAST64 ". %s", HandleToUint64(mem),
4402315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                           validation_error_map[VALIDATION_ERROR_33600562]);
44035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
4404de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        mem_info->mem_range.size = 0;
44055f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski        if (mem_info->shadow_copy) {
44065f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            free(mem_info->shadow_copy_base);
44075f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_copy_base = 0;
44085f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_copy = 0;
44095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
44105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
44113251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
44125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
44135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
44145f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski// Guard value for pad data
44155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisstatic char NoncoherentMemoryFillValue = 0xb;
44165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
44175f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinskistatic void initializeAndTrackMemory(layer_data *dev_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size,
44185f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                     void **ppData) {
44199a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto mem_info = GetMemObjInfo(dev_data, mem);
442057fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis    if (mem_info) {
4421de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        mem_info->p_driver_data = *ppData;
4422de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis        uint32_t index = mem_info->alloc_info.memoryTypeIndex;
4423b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis        if (dev_data->phys_dev_mem_props.memoryTypes[index].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) {
44245f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_copy = 0;
44255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
44265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (size == VK_WHOLE_SIZE) {
44275f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                size = mem_info->alloc_info.allocationSize - offset;
44285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
44295f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_pad_size = dev_data->phys_dev_properties.properties.limits.minMemoryMapAlignment;
443016769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton            assert(SafeModulo(mem_info->shadow_pad_size,
44315f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                  dev_data->phys_dev_properties.properties.limits.minMemoryMapAlignment) == 0);
44325f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            // Ensure start of mapped region reflects hardware alignment constraints
44335f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            uint64_t map_alignment = dev_data->phys_dev_properties.properties.limits.minMemoryMapAlignment;
44345f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski
44355f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            // From spec: (ppData - offset) must be aligned to at least limits::minMemoryMapAlignment.
44365f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            uint64_t start_offset = offset % map_alignment;
44375f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            // Data passed to driver will be wrapped by a guardband of data to detect over- or under-writes.
4438bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            mem_info->shadow_copy_base =
4439bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                malloc(static_cast<size_t>(2 * mem_info->shadow_pad_size + size + map_alignment + start_offset));
44405f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski
44415f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            mem_info->shadow_copy =
44425f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                reinterpret_cast<char *>((reinterpret_cast<uintptr_t>(mem_info->shadow_copy_base) + map_alignment) &
4443bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         ~(map_alignment - 1)) +
4444bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                start_offset;
444516769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton            assert(SafeModulo(reinterpret_cast<uintptr_t>(mem_info->shadow_copy) + mem_info->shadow_pad_size - start_offset,
44465f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                  map_alignment) == 0);
44475f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski
44486e17c244b21ce43ac57404a00a0d844039eed363Mark Lobodzinski            memset(mem_info->shadow_copy, NoncoherentMemoryFillValue, static_cast<size_t>(2 * mem_info->shadow_pad_size + size));
44495f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            *ppData = static_cast<char *>(mem_info->shadow_copy) + mem_info->shadow_pad_size;
44505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
44515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
44525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
44535f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski
4454a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis// Verify that state for fence being waited on is appropriate. That is,
44559867daedbf52debc77d6568162ee21e071699b80Chris Forbes//  a fence being waited on should not already be signaled and
4456a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis//  it should have been submitted on a queue or during acquire next image
445749f6132af865afd5b7f413c91125971ac97c135aChris Forbesstatic inline bool verifyWaitFenceState(layer_data *dev_data, VkFence fence, const char *apiCall) {
44583251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
44599b48b44dd917f95b5f34dd629ec4076fc87eb3a2Chris Forbes
44609a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pFence = GetFenceNode(dev_data, fence);
44619b48b44dd917f95b5f34dd629ec4076fc87eb3a2Chris Forbes    if (pFence) {
4462cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes        if (pFence->state == FENCE_UNSIGNALED) {
44633251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
44649b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(fence), __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM",
44653251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "%s called for fence 0x%" PRIxLEAST64
44663251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            " which has not been submitted on a Queue or during "
44673251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "acquire next image.",
44689b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            apiCall, HandleToUint64(fence));
44695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
44705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
44713251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
44725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
4473a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis
4474b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlisstatic void RetireFence(layer_data *dev_data, VkFence fence) {
44759a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pFence = GetFenceNode(dev_data, fence);
4476b3ecd4c1fb44a2e65dfc13256afa9150aabde1d4Chris Forbes    if (pFence->signaler.first != VK_NULL_HANDLE) {
447725002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Fence signaller is a queue -- use this as proof that prior operations on that queue have completed.
44789a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        RetireWorkOnQueue(dev_data, GetQueueState(dev_data, pFence->signaler.first), pFence->signaler.second);
4479bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    } else {
448025002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // Fence signaller is the WSI. We're not tracking what the WSI op actually /was/ in CV yet, but we need to mark
448125002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // the fence as retired.
4482d4513979120463171eb479cdded9336eb9944da1Chris Forbes        pFence->state = FENCE_RETIRED;
4483d4513979120463171eb479cdded9336eb9944da1Chris Forbes    }
4484b3ecd4c1fb44a2e65dfc13256afa9150aabde1d4Chris Forbes}
4485b3ecd4c1fb44a2e65dfc13256afa9150aabde1d4Chris Forbes
4486accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlisstatic bool PreCallValidateWaitForFences(layer_data *dev_data, uint32_t fence_count, const VkFence *fences) {
4487cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.wait_for_fences) return false;
4488accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    bool skip = false;
4489accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    for (uint32_t i = 0; i < fence_count; i++) {
4490accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis        skip |= verifyWaitFenceState(dev_data, fences[i], "vkWaitForFences");
4491b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis        skip |= VerifyQueueStateToFence(dev_data, fences[i]);
4492accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    }
4493accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    return skip;
4494accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis}
4495accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis
4496b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlisstatic void PostCallRecordWaitForFences(layer_data *dev_data, uint32_t fence_count, const VkFence *fences, VkBool32 wait_all) {
4497b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    // When we know that all fences are complete we can clean/remove their CBs
4498accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    if ((VK_TRUE == wait_all) || (1 == fence_count)) {
4499accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis        for (uint32_t i = 0; i < fence_count; i++) {
4500b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis            RetireFence(dev_data, fences[i]);
4501accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis        }
4502accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    }
4503accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    // NOTE : Alternate case not handled here is when some fences have completed. In
4504accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    //  this case for app to guarantee which fences completed it will have to call
4505b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis    //  vkGetFenceStatus() at which point we'll clean/remove their CBs if complete.
4506accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis}
4507accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis
4508bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL WaitForFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences, VkBool32 waitAll,
4509bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                             uint64_t timeout) {
451056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
45115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Verify fence status of submitted fences
4512b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
4513accdf1d467e269e05b89764faf204fb2ff600b57Tobin Ehlis    bool skip = PreCallValidateWaitForFences(dev_data, fenceCount, pFences);
4514b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
4515cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
4516a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis
45174a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.WaitForFences(device, fenceCount, pFences, waitAll, timeout);
4518414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller
45195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
4520b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
4521b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis        PostCallRecordWaitForFences(dev_data, fenceCount, pFences, waitAll);
4522b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
45235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
45245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
45255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
45265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4527f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlisstatic bool PreCallValidateGetFenceStatus(layer_data *dev_data, VkFence fence) {
4528cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.get_fence_state) return false;
4529f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis    return verifyWaitFenceState(dev_data, fence, "vkGetFenceStatus");
4530f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis}
4531f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis
4532b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlisstatic void PostCallRecordGetFenceStatus(layer_data *dev_data, VkFence fence) { RetireFence(dev_data, fence); }
4533f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis
453489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL GetFenceStatus(VkDevice device, VkFence fence) {
453556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
4536b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
4537f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis    bool skip = PreCallValidateGetFenceStatus(dev_data, fence);
4538b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
4539cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
4540a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis
45414a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.GetFenceStatus(device, fence);
45425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
4543f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis        lock.lock();
4544b7d814f72a72fb2eee7efa0f48e6a67a86eaf588Tobin Ehlis        PostCallRecordGetFenceStatus(dev_data, fence);
4545f073b96e7a0030b55a66b780bd3ed57262cf1fa2Tobin Ehlis        lock.unlock();
45465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
45475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
45485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
45495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
45503b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlisstatic void PostCallRecordGetDeviceQueue(layer_data *dev_data, uint32_t q_family_index, VkQueue queue) {
45513b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    // Add queue to tracking set only if it is new
45523b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    auto result = dev_data->queues.emplace(queue);
45533b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    if (result.second == true) {
455436c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlis        QUEUE_STATE *queue_state = &dev_data->queueMap[queue];
45553b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis        queue_state->queue = queue;
45563b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis        queue_state->queueFamilyIndex = q_family_index;
45573b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis        queue_state->seq = 0;
45583b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    }
45593b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis}
45603b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis
4561bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL GetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue *pQueue) {
456256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
45634a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.GetDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue);
4564b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::lock_guard<std::mutex> lock(global_lock);
4565b376edacad6f7ab3fcc0a914e9b1673a9fcd5143Mark Lobodzinski
45663b3fccc991a6cbe649b96880f36d90318b3c7cc2Tobin Ehlis    PostCallRecordGetDeviceQueue(dev_data, queueFamilyIndex, *pQueue);
45675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
45685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
456936c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic bool PreCallValidateQueueWaitIdle(layer_data *dev_data, VkQueue queue, QUEUE_STATE **queue_state) {
45709a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *queue_state = GetQueueState(dev_data, queue);
4571cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.queue_wait_idle) return false;
4572e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis    return VerifyQueueStateToSeq(dev_data, *queue_state, (*queue_state)->seq + (*queue_state)->submissions.size());
45734273a1c157585a645dca4c960086032793899d05Tobin Ehlis}
45744273a1c157585a645dca4c960086032793899d05Tobin Ehlis
457536c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlisstatic void PostCallRecordQueueWaitIdle(layer_data *dev_data, QUEUE_STATE *queue_state) {
4576e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis    RetireWorkOnQueue(dev_data, queue_state, queue_state->seq + queue_state->submissions.size());
45774273a1c157585a645dca4c960086032793899d05Tobin Ehlis}
45784273a1c157585a645dca4c960086032793899d05Tobin Ehlis
457989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL QueueWaitIdle(VkQueue queue) {
458056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
458136c3a4fe8455762d2dc0b2b9ece44675a3ee8d97Tobin Ehlis    QUEUE_STATE *queue_state = nullptr;
45829867daedbf52debc77d6568162ee21e071699b80Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
45834273a1c157585a645dca4c960086032793899d05Tobin Ehlis    bool skip = PreCallValidateQueueWaitIdle(dev_data, queue, &queue_state);
45849867daedbf52debc77d6568162ee21e071699b80Chris Forbes    lock.unlock();
4585cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
45864a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.QueueWaitIdle(queue);
45874273a1c157585a645dca4c960086032793899d05Tobin Ehlis    if (VK_SUCCESS == result) {
4588e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis        lock.lock();
4589e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis        PostCallRecordQueueWaitIdle(dev_data, queue_state);
4590e0cec9ec6dd3cfd83345cabba55ec021681801dbTobin Ehlis        lock.unlock();
45914273a1c157585a645dca4c960086032793899d05Tobin Ehlis    }
45925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
45935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
45945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
45958767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlisstatic bool PreCallValidateDeviceWaitIdle(layer_data *dev_data) {
4596cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.device_wait_idle) return false;
45978767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    bool skip = false;
45988767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    for (auto &queue : dev_data->queueMap) {
45998767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        skip |= VerifyQueueStateToSeq(dev_data, &queue.second, queue.second.seq + queue.second.submissions.size());
46008767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    }
46018767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    return skip;
46028767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis}
46038767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis
46048767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlisstatic void PostCallRecordDeviceWaitIdle(layer_data *dev_data) {
46058767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    for (auto &queue : dev_data->queueMap) {
46068767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        RetireWorkOnQueue(dev_data, &queue.second, queue.second.seq + queue.second.submissions.size());
46078767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    }
46088767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis}
46098767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis
461089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL DeviceWaitIdle(VkDevice device) {
461156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
4612b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
46138767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    bool skip = PreCallValidateDeviceWaitIdle(dev_data);
4614b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
4615cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
46164a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.DeviceWaitIdle(device);
46178767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    if (VK_SUCCESS == result) {
46188767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        lock.lock();
46198767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        PostCallRecordDeviceWaitIdle(dev_data);
46208767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis        lock.unlock();
46218767ceaf6a7d5675c2fe0502df31a1339a5a6337Tobin Ehlis    }
46225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
46235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
46245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
46251d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlisstatic bool PreCallValidateDestroyFence(layer_data *dev_data, VkFence fence, FENCE_NODE **fence_node, VK_OBJECT *obj_struct) {
46269a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *fence_node = GetFenceNode(dev_data, fence);
46279b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    *obj_struct = {HandleToUint64(fence), kVulkanObjectTypeFence};
4628cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_fence) return false;
46291d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    bool skip = false;
46301d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    if (*fence_node) {
46311d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        if ((*fence_node)->state == FENCE_INFLIGHT) {
46321d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
4633315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(fence), __LINE__, VALIDATION_ERROR_24e008c0, "DS", "Fence 0x%" PRIx64 " is in use. %s",
4634315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(fence), validation_error_map[VALIDATION_ERROR_24e008c0]);
46351d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        }
46361d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    }
46371d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    return skip;
46381d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis}
46391d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis
46401d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlisstatic void PostCallRecordDestroyFence(layer_data *dev_data, VkFence fence) { dev_data->fenceMap.erase(fence); }
46411d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis
464289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL DestroyFence(VkDevice device, VkFence fence, const VkAllocationCallbacks *pAllocator) {
464356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
46441d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    // Common data objects used pre & post call
46451d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    FENCE_NODE *fence_node = nullptr;
46461d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    VK_OBJECT obj_struct;
4647b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
46481d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    bool skip = PreCallValidateDestroyFence(dev_data, fence, &fence_node, &obj_struct);
46491344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
46501d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    if (!skip) {
46511d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        lock.unlock();
46524a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyFence(device, fence, pAllocator);
46531d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        lock.lock();
46541d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis        PostCallRecordDestroyFence(dev_data, fence);
46551d3dce01906e45faf7282cffc3334cbda1662656Tobin Ehlis    }
46565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
46575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4658c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlisstatic bool PreCallValidateDestroySemaphore(layer_data *dev_data, VkSemaphore semaphore, SEMAPHORE_NODE **sema_node,
4659c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis                                            VK_OBJECT *obj_struct) {
46609a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *sema_node = GetSemaphoreNode(dev_data, semaphore);
46619b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    *obj_struct = {HandleToUint64(semaphore), kVulkanObjectTypeSemaphore};
4662cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_semaphore) return false;
4663c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    bool skip = false;
4664c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    if (*sema_node) {
4665315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *sema_node, *obj_struct, VALIDATION_ERROR_268008e2);
4666c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    }
4667c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    return skip;
4668c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis}
4669c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis
4670c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlisstatic void PostCallRecordDestroySemaphore(layer_data *dev_data, VkSemaphore sema) { dev_data->semaphoreMap.erase(sema); }
4671c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis
4672bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroySemaphore(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks *pAllocator) {
467356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
4674c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    SEMAPHORE_NODE *sema_node;
4675c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    VK_OBJECT obj_struct;
4676e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
4677c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis    bool skip = PreCallValidateDestroySemaphore(dev_data, semaphore, &sema_node, &obj_struct);
4678eafbf0b68ee6ea6e0bf33f07e0058d00a96efd9aTobin Ehlis    if (!skip) {
4679eafbf0b68ee6ea6e0bf33f07e0058d00a96efd9aTobin Ehlis        lock.unlock();
46804a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroySemaphore(device, semaphore, pAllocator);
4681c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis        lock.lock();
4682c0f1f8368ec7be6f098e2599b31622f81ff00185Tobin Ehlis        PostCallRecordDestroySemaphore(dev_data, semaphore);
468399d938c90c2f000ee73fb13513dacf84ffa5651fMark Mueller    }
46845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
46855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
46864710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlisstatic bool PreCallValidateDestroyEvent(layer_data *dev_data, VkEvent event, EVENT_STATE **event_state, VK_OBJECT *obj_struct) {
46879a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *event_state = GetEventNode(dev_data, event);
46889b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    *obj_struct = {HandleToUint64(event), kVulkanObjectTypeEvent};
4689cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_event) return false;
4690d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    bool skip = false;
4691d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    if (*event_state) {
4692315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *event_state, *obj_struct, VALIDATION_ERROR_24c008f2);
4693d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    }
4694d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    return skip;
4695d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis}
4696d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis
46974710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlisstatic void PostCallRecordDestroyEvent(layer_data *dev_data, VkEvent event, EVENT_STATE *event_state, VK_OBJECT obj_struct) {
469839c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, event_state->cb_bindings, obj_struct);
4699d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    dev_data->eventMap.erase(event);
4700d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis}
4701d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis
470289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL DestroyEvent(VkDevice device, VkEvent event, const VkAllocationCallbacks *pAllocator) {
470356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
47044710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis    EVENT_STATE *event_state = nullptr;
4705d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    VK_OBJECT obj_struct;
4706b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
4707d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis    bool skip = PreCallValidateDestroyEvent(dev_data, event, &event_state, &obj_struct);
4708f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    if (!skip) {
4709f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis        lock.unlock();
47104a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyEvent(device, event, pAllocator);
4711d379c77e4254a740aa838a82e7af186525524617Tobin Ehlis        lock.lock();
4712405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (event != VK_NULL_HANDLE) {
4713405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyEvent(dev_data, event, event_state, obj_struct);
4714405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
4715f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    }
47165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
47175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
471883c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlisstatic bool PreCallValidateDestroyQueryPool(layer_data *dev_data, VkQueryPool query_pool, QUERY_POOL_NODE **qp_state,
471983c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis                                            VK_OBJECT *obj_struct) {
47209a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *qp_state = GetQueryPoolNode(dev_data, query_pool);
47219b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    *obj_struct = {HandleToUint64(query_pool), kVulkanObjectTypeQueryPool};
4722cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_query_pool) return false;
472383c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    bool skip = false;
472483c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    if (*qp_state) {
4725315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *qp_state, *obj_struct, VALIDATION_ERROR_26200632);
472683c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    }
472783c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    return skip;
472883c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis}
472983c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis
4730bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic void PostCallRecordDestroyQueryPool(layer_data *dev_data, VkQueryPool query_pool, QUERY_POOL_NODE *qp_state,
4731bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           VK_OBJECT obj_struct) {
473283c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    invalidateCommandBuffers(dev_data, qp_state->cb_bindings, obj_struct);
473383c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    dev_data->queryPoolMap.erase(query_pool);
473483c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis}
473583c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis
4736bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks *pAllocator) {
473756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
473883c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    QUERY_POOL_NODE *qp_state = nullptr;
473983c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    VK_OBJECT obj_struct;
4740ccdcc9686c664e9407dd03262f3aaf3245b23be2Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
474183c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis    bool skip = PreCallValidateDestroyQueryPool(dev_data, queryPool, &qp_state, &obj_struct);
4742f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    if (!skip) {
4743f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis        lock.unlock();
47444a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyQueryPool(device, queryPool, pAllocator);
474583c1f2cdfb8eca95c7d450aca7863d5b269b7be6Tobin Ehlis        lock.lock();
4746405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (queryPool != VK_NULL_HANDLE) {
4747405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyQueryPool(dev_data, queryPool, qp_state, obj_struct);
4748405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
4749f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    }
47505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
47519fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlisstatic bool PreCallValidateGetQueryPoolResults(layer_data *dev_data, VkQueryPool query_pool, uint32_t first_query,
47529fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                               uint32_t query_count, VkQueryResultFlags flags,
47539fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                               unordered_map<QueryObject, vector<VkCommandBuffer>> *queries_in_flight) {
4754a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes    // TODO: clean this up, it's insanely wasteful.
4755a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes    for (auto cmd_buffer : dev_data->commandBufferMap) {
4756a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes        if (cmd_buffer.second->in_use.load()) {
4757a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes            for (auto query_state_pair : cmd_buffer.second->queryToStateMap) {
4758a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes                (*queries_in_flight)[query_state_pair.first].push_back(
4759a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes                    cmd_buffer.first);
4760a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes            }
47615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
47625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
4763cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.get_query_pool_results) return false;
47649fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    bool skip = false;
47659fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    for (uint32_t i = 0; i < query_count; ++i) {
47669fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        QueryObject query = {query_pool, first_query + i};
47679fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        auto qif_pair = queries_in_flight->find(query);
47689fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        auto query_state_pair = dev_data->queryToStateMap.find(query);
47699fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        if (query_state_pair != dev_data->queryToStateMap.end()) {
4770ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski            // Available and in flight
47719fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            if (qif_pair != queries_in_flight->end() && query_state_pair != dev_data->queryToStateMap.end() &&
47729fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                query_state_pair->second) {
47739fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                for (auto cmd_buffer : qif_pair->second) {
47749a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto cb = GetCBNode(dev_data, cmd_buffer);
47759fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    auto query_event_pair = cb->waitedEventsBeforeQueryReset.find(query);
47769fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    if (query_event_pair == cb->waitedEventsBeforeQueryReset.end()) {
47779fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
47789fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                        VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
47799fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                        "Cannot get query results on queryPool 0x%" PRIx64 " with index %d which is in flight.",
47809b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                        HandleToUint64(query_pool), first_query + i);
4781ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                    }
4782ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                }
4783ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                // Unavailable and in flight
47849fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            } else if (qif_pair != queries_in_flight->end() && query_state_pair != dev_data->queryToStateMap.end() &&
47859fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                       !query_state_pair->second) {
4786ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                // TODO : Can there be the same query in use by multiple command buffers in flight?
4787ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                bool make_available = false;
47889fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                for (auto cmd_buffer : qif_pair->second) {
47899a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto cb = GetCBNode(dev_data, cmd_buffer);
47909fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    make_available |= cb->queryToStateMap[query];
4791ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                }
4792ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                if (!(((flags & VK_QUERY_RESULT_PARTIAL_BIT) || (flags & VK_QUERY_RESULT_WAIT_BIT)) && make_available)) {
47939fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
47949fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                    VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
47959fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                    "Cannot get query results on queryPool 0x%" PRIx64 " with index %d which is unavailable.",
47969b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    HandleToUint64(query_pool), first_query + i);
47975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
4798ec27ab7d1aa03fa187755b6720e1be995a994f5cMark Lobodzinski                // Unavailable
47999fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            } else if (query_state_pair != dev_data->queryToStateMap.end() && !query_state_pair->second) {
48009fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0,
48019fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
48029fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                "Cannot get query results on queryPool 0x%" PRIx64 " with index %d which is unavailable.",
48039b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(query_pool), first_query + i);
48049fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                // Uninitialized
48059fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            } else if (query_state_pair == dev_data->queryToStateMap.end()) {
48069fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0,
48079fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
48089fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                "Cannot get query results on queryPool 0x%" PRIx64
48099fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                " with index %d as data has not been collected for this index.",
48109b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(query_pool), first_query + i);
48115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
48125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
48135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
48149fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    return skip;
48159fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis}
48169fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis
48179fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlisstatic void PostCallRecordGetQueryPoolResults(layer_data *dev_data, VkQueryPool query_pool, uint32_t first_query,
48189fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                              uint32_t query_count,
48199fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                              unordered_map<QueryObject, vector<VkCommandBuffer>> *queries_in_flight) {
48209fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    for (uint32_t i = 0; i < query_count; ++i) {
48219fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        QueryObject query = {query_pool, first_query + i};
48229fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        auto qif_pair = queries_in_flight->find(query);
48239fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        auto query_state_pair = dev_data->queryToStateMap.find(query);
48249fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        if (query_state_pair != dev_data->queryToStateMap.end()) {
48259fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            // Available and in flight
48269fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            if (qif_pair != queries_in_flight->end() && query_state_pair != dev_data->queryToStateMap.end() &&
48279fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                query_state_pair->second) {
48289fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                for (auto cmd_buffer : qif_pair->second) {
48299a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto cb = GetCBNode(dev_data, cmd_buffer);
48309fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    auto query_event_pair = cb->waitedEventsBeforeQueryReset.find(query);
48319fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    if (query_event_pair != cb->waitedEventsBeforeQueryReset.end()) {
48329fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                        for (auto event : query_event_pair->second) {
48339fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                            dev_data->eventMap[event].needsSignaled = true;
48349fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                        }
48359fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                    }
48369fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                }
48379fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis            }
48389fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        }
48399fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    }
48409fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis}
48419fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis
48429fdee42cd357379efb9aa27f90beb75d1f824955Tobin EhlisVKAPI_ATTR VkResult VKAPI_CALL GetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount,
48439fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis                                                   size_t dataSize, void *pData, VkDeviceSize stride, VkQueryResultFlags flags) {
484456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
48459fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    unordered_map<QueryObject, vector<VkCommandBuffer>> queries_in_flight;
48469fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
48479fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    bool skip = PreCallValidateGetQueryPoolResults(dev_data, queryPool, firstQuery, queryCount, flags, &queries_in_flight);
4848b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
4849cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
48509fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    VkResult result =
48519fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis        dev_data->dispatch_table.GetQueryPoolResults(device, queryPool, firstQuery, queryCount, dataSize, pData, stride, flags);
48529fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    lock.lock();
48539fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    PostCallRecordGetQueryPoolResults(dev_data, queryPool, firstQuery, queryCount, &queries_in_flight);
48549fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    lock.unlock();
48559fdee42cd357379efb9aa27f90beb75d1f824955Tobin Ehlis    return result;
48565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
48575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
4858825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Return true if given ranges intersect, else false
4859825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Prereq : For both ranges, range->end - range->start > 0. This case should have already resulted
4860825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  in an error so not checking that here
4861825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// pad_ranges bool indicates a linear and non-linear comparison which requires padding
48623251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski// In the case where padding is required, if an alias is encountered then a validation error is reported and skip
48633251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski//  may be set by the callback function so caller should merge in skip value if padding case is possible.
48642ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Stratton// This check can be skipped by passing skip_checks=true, for call sites outside the validation path.
48653251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinskistatic bool rangesIntersect(layer_data const *dev_data, MEMORY_RANGE const *range1, MEMORY_RANGE const *range2, bool *skip,
48662ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Stratton                            bool skip_checks) {
48673251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    *skip = false;
4868825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto r1_start = range1->start;
4869825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto r1_end = range1->end;
4870825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto r2_start = range2->start;
4871825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto r2_end = range2->end;
4872825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    VkDeviceSize pad_align = 1;
4873825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    if (range1->linear != range2->linear) {
4874825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        pad_align = dev_data->phys_dev_properties.properties.limits.bufferImageGranularity;
4875825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    }
4876cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if ((r1_end & ~(pad_align - 1)) < (r2_start & ~(pad_align - 1))) return false;
4877cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if ((r1_start & ~(pad_align - 1)) > (r2_end & ~(pad_align - 1))) return false;
487847aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
48792ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Stratton    if (!skip_checks && (range1->linear != range2->linear)) {
488053ecec26e80e4d18b57d24ed6eb91a3c9da4b95cTobin Ehlis        // In linear vs. non-linear case, warn of aliasing
4881825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        const char *r1_linear_str = range1->linear ? "Linear" : "Non-linear";
4882825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        const char *r1_type_str = range1->image ? "image" : "buffer";
4883825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        const char *r2_linear_str = range2->linear ? "linear" : "non-linear";
4884825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        const char *r2_type_str = range2->image ? "image" : "buffer";
4885825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        auto obj_type = range1->image ? VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT : VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT;
48863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        *skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, obj_type, range1->handle, 0,
48873251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                         MEMTRACK_INVALID_ALIASING, "MEM", "%s %s 0x%" PRIx64 " is aliased with %s %s 0x%" PRIx64
48883251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                           " which may indicate a bug. For further info refer to the "
48893251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                           "Buffer-Image Granularity section of the Vulkan specification. "
48903251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                           "(https://www.khronos.org/registry/vulkan/specs/1.0-extensions/"
48913251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                           "xhtml/vkspec.html#resources-bufferimagegranularity)",
48923251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                         r1_linear_str, r1_type_str, range1->handle, r2_linear_str, r2_type_str, range2->handle);
489347aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    }
4894825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    // Ranges intersect
4895825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    return true;
489647aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski}
4897623548a271287ae55415e45e3c654ee66d4e79ffTobin Ehlis// Simplified rangesIntersect that calls above function to check range1 for intersection with offset & end addresses
4898c3340a06ecac4d7b9540592cae339f8fc224d0b1Mark Lobodzinskibool rangesIntersect(layer_data const *dev_data, MEMORY_RANGE const *range1, VkDeviceSize offset, VkDeviceSize end) {
4899825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    // Create a local MEMORY_RANGE struct to wrap offset/size
4900825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    MEMORY_RANGE range_wrap;
4901825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    // Synch linear with range1 to avoid padding and potential validation error case
4902825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range_wrap.linear = range1->linear;
4903825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range_wrap.start = offset;
4904cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    range_wrap.end = end;
4905825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    bool tmp_bool;
49062ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Stratton    return rangesIntersect(dev_data, range1, &range_wrap, &tmp_bool, true);
4907825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis}
4908cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis// For given mem_info, set all ranges valid that intersect [offset-end] range
4909cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis// TODO : For ranges where there is no alias, we may want to create new buffer ranges that are valid
4910cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlisstatic void SetMemRangesValid(layer_data const *dev_data, DEVICE_MEM_INFO *mem_info, VkDeviceSize offset, VkDeviceSize end) {
4911cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    bool tmp_bool = false;
4912f6e16b28b808a342cb92768001afa2cfeee08a11Tobin Ehlis    MEMORY_RANGE map_range = {};
4913cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    map_range.linear = true;
4914cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    map_range.start = offset;
4915cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    map_range.end = end;
4916cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    for (auto &handle_range_pair : mem_info->bound_ranges) {
49172ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Stratton        if (rangesIntersect(dev_data, &handle_range_pair.second, &map_range, &tmp_bool, false)) {
4918cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis            // TODO : WARN here if tmp_bool true?
4919cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis            handle_range_pair.second.valid = true;
4920cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis        }
4921cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    }
4922cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis}
49230ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
49240ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Strattonstatic bool ValidateInsertMemoryRange(layer_data const *dev_data, uint64_t handle, DEVICE_MEM_INFO *mem_info,
49250ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                      VkDeviceSize memoryOffset, VkMemoryRequirements memRequirements, bool is_image,
49260ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                      bool is_linear, const char *api_name) {
49270ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    bool skip = false;
49280ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
49290ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    MEMORY_RANGE range;
49300ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.image = is_image;
49310ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.handle = handle;
49320ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.linear = is_linear;
49330ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.valid = mem_info->global_valid;
49340ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.memory = mem_info->mem;
49350ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.start = memoryOffset;
49360ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.size = memRequirements.size;
49370ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.end = memoryOffset + memRequirements.size - 1;
49380ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    range.aliases.clear();
49390ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
49400ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    // Check for aliasing problems.
49410ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    for (auto &obj_range_pair : mem_info->bound_ranges) {
49420ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        auto check_range = &obj_range_pair.second;
49430ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        bool intersection_error = false;
49442ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Stratton        if (rangesIntersect(dev_data, &range, check_range, &intersection_error, false)) {
49450ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton            skip |= intersection_error;
49460ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton            range.aliases.insert(check_range);
49470ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        }
49480ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    }
49490ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
49500ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    if (memoryOffset >= mem_info->alloc_info.allocationSize) {
4951315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        UNIQUE_VALIDATION_ERROR_CODE error_code = is_image ? VALIDATION_ERROR_1740082c : VALIDATION_ERROR_1700080e;
49520ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
49539b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       HandleToUint64(mem_info->mem), __LINE__, error_code, "MEM",
49540ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                       "In %s, attempting to bind memory (0x%" PRIxLEAST64 ") to object (0x%" PRIxLEAST64
49550ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                       "), memoryOffset=0x%" PRIxLEAST64 " must be less than the memory allocation size 0x%" PRIxLEAST64 ". %s",
49569b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       api_name, HandleToUint64(mem_info->mem), handle, memoryOffset, mem_info->alloc_info.allocationSize,
49579b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       validation_error_map[error_code]);
49580ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    }
49590ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
49600ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton    return skip;
49610ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton}
49620ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
4963825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Object with given handle is being bound to memory w/ given mem_info struct.
4964825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  Track the newly bound memory range with given memoryOffset
4965825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  Also scan any previous ranges, track aliased ranges with new range, and flag an error if a linear
4966825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  and non-linear range incorrectly overlap.
4967825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Return true if an error is flagged and the user callback returns "true", otherwise false
4968825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// is_image indicates an image object, otherwise handle is for a buffer
4969825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// is_linear indicates a buffer or linear image
49700ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Strattonstatic void InsertMemoryRange(layer_data const *dev_data, uint64_t handle, DEVICE_MEM_INFO *mem_info, VkDeviceSize memoryOffset,
49710ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                              VkMemoryRequirements memRequirements, bool is_image, bool is_linear) {
49725360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    MEMORY_RANGE range;
4973825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
4974825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range.image = is_image;
497547aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    range.handle = handle;
4976825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range.linear = is_linear;
4977f541bf53dee6daf82a4c8304354eac599a884d29Tobin Ehlis    range.valid = mem_info->global_valid;
4978825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range.memory = mem_info->mem;
497947aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    range.start = memoryOffset;
4980825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    range.size = memRequirements.size;
498147aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    range.end = memoryOffset + memRequirements.size - 1;
49825360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    range.aliases.clear();
49835360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    // Update Memory aliasing
498475f4c8cec0996021a4258b9bf920a9e0fea4eac1Tobin 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
49855360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    // inserted into map before loop to get the final ptr, then we may enter loop when not needed & we check range against itself
49865360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    std::unordered_set<MEMORY_RANGE *> tmp_alias_ranges;
4987825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    for (auto &obj_range_pair : mem_info->bound_ranges) {
4988825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        auto check_range = &obj_range_pair.second;
49895360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis        bool intersection_error = false;
49902ea938737c34152a86f5e453eaef7f77b45c0ea3Cort Stratton        if (rangesIntersect(dev_data, &range, check_range, &intersection_error, true)) {
4991825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis            range.aliases.insert(check_range);
49925360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis            tmp_alias_ranges.insert(check_range);
4993825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        }
4994825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    }
49955360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    mem_info->bound_ranges[handle] = std::move(range);
49965360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    for (auto tmp_range : tmp_alias_ranges) {
49975360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis        tmp_range->aliases.insert(&mem_info->bound_ranges[handle]);
49985360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    }
4999825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    if (is_image)
5000825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        mem_info->bound_images.insert(handle);
5001825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    else
5002825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        mem_info->bound_buffers.insert(handle);
500347aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski}
500447aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
50050ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Strattonstatic bool ValidateInsertImageMemoryRange(layer_data const *dev_data, VkImage image, DEVICE_MEM_INFO *mem_info,
50060ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                           VkDeviceSize mem_offset, VkMemoryRequirements mem_reqs, bool is_linear,
50070ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                           const char *api_name) {
50089b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    return ValidateInsertMemoryRange(dev_data, HandleToUint64(image), mem_info, mem_offset, mem_reqs, true, is_linear, api_name);
50090ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton}
50100ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Strattonstatic void InsertImageMemoryRange(layer_data const *dev_data, VkImage image, DEVICE_MEM_INFO *mem_info, VkDeviceSize mem_offset,
50110ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                   VkMemoryRequirements mem_reqs, bool is_linear) {
50129b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    InsertMemoryRange(dev_data, HandleToUint64(image), mem_info, mem_offset, mem_reqs, true, is_linear);
5013825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis}
5014825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
50150ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Strattonstatic bool ValidateInsertBufferMemoryRange(layer_data const *dev_data, VkBuffer buffer, DEVICE_MEM_INFO *mem_info,
50160ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                            VkDeviceSize mem_offset, VkMemoryRequirements mem_reqs, const char *api_name) {
50179b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    return ValidateInsertMemoryRange(dev_data, HandleToUint64(buffer), mem_info, mem_offset, mem_reqs, false, true, api_name);
50180ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton}
50190ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Strattonstatic void InsertBufferMemoryRange(layer_data const *dev_data, VkBuffer buffer, DEVICE_MEM_INFO *mem_info, VkDeviceSize mem_offset,
50200ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                    VkMemoryRequirements mem_reqs) {
50219b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    InsertMemoryRange(dev_data, HandleToUint64(buffer), mem_info, mem_offset, mem_reqs, false, true);
5022825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis}
5023825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
5024825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis// Remove MEMORY_RANGE struct for give handle from bound_ranges of mem_info
5025825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  is_image indicates if handle is for image or buffer
5026825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  This function will also remove the handle-to-index mapping from the appropriate
5027825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis//  map and clean up any aliases for range being removed.
5028825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlisstatic void RemoveMemoryRange(uint64_t handle, DEVICE_MEM_INFO *mem_info, bool is_image) {
5029825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    auto erase_range = &mem_info->bound_ranges[handle];
5030825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    for (auto alias_range : erase_range->aliases) {
5031825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        alias_range->aliases.erase(erase_range);
503247aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    }
50335360871dd546e8aa7c1a273e9036c201fe4e3ffbTobin Ehlis    erase_range->aliases.clear();
5034825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis    mem_info->bound_ranges.erase(handle);
50351cba4e1b5940c6818572e05dcad5a3a47fafbc9eTobin Ehlis    if (is_image) {
5036825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        mem_info->bound_images.erase(handle);
50371cba4e1b5940c6818572e05dcad5a3a47fafbc9eTobin Ehlis    } else {
5038825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis        mem_info->bound_buffers.erase(handle);
50391cba4e1b5940c6818572e05dcad5a3a47fafbc9eTobin Ehlis    }
504047aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski}
504147aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
5042842b2d28ded1c6e2c38491a81213d0e1d1b7295aMark Lobodzinskivoid RemoveBufferMemoryRange(uint64_t handle, DEVICE_MEM_INFO *mem_info) { RemoveMemoryRange(handle, mem_info, false); }
5043825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
50448c59133586421be878d393799b30044497f77727Mark Lobodzinskivoid RemoveImageMemoryRange(uint64_t handle, DEVICE_MEM_INFO *mem_info) { RemoveMemoryRange(handle, mem_info, true); }
5045825446075d5f6c6b531754c0709bddd9dae8945fTobin Ehlis
5046bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator) {
504756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5048e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    BUFFER_STATE *buffer_state = nullptr;
5049e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    VK_OBJECT obj_struct;
5050b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5051e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    bool skip = PreCallValidateDestroyBuffer(dev_data, buffer, &buffer_state, &obj_struct);
5052e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis    if (!skip) {
5053b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
50544a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyBuffer(device, buffer, pAllocator);
5055e1056daefb39e3a3fed0088874725c56a1359e54Tobin Ehlis        lock.lock();
5056405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (buffer != VK_NULL_HANDLE) {
5057405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyBuffer(dev_data, buffer, buffer_state, obj_struct);
5058405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
505947aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski    }
50605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
50615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5062bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyBufferView(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks *pAllocator) {
506356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5064f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    // Common data objects used pre & post call
50658e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    BUFFER_VIEW_STATE *buffer_view_state = nullptr;
50668e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    VK_OBJECT obj_struct;
5067a123662876eebfa844faa65ae3f071d3d77618ebTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
50688e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    // Validate state before calling down chain, update common data if we'll be calling down chain
50698e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis    bool skip = PreCallValidateDestroyBufferView(dev_data, bufferView, &buffer_view_state, &obj_struct);
507038e26abbaa884eb48bfec4ddb4e0ae2c90634e06Tobin Ehlis    if (!skip) {
507138e26abbaa884eb48bfec4ddb4e0ae2c90634e06Tobin Ehlis        lock.unlock();
50724a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyBufferView(device, bufferView, pAllocator);
50738e0ffae5b5c87fa062229b8c003be10c7e48aea1Tobin Ehlis        lock.lock();
5074405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (bufferView != VK_NULL_HANDLE) {
5075405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyBufferView(dev_data, bufferView, buffer_view_state, obj_struct);
5076405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
50775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
50785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
50795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
50802a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin EhlisVKAPI_ATTR void VKAPI_CALL DestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) {
508156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
50821facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    IMAGE_STATE *image_state = nullptr;
50832a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    VK_OBJECT obj_struct;
50842a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
50852a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    bool skip = PreCallValidateDestroyImage(dev_data, image, &image_state, &obj_struct);
50862a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis    if (!skip) {
5087f940225c9e5e3e14b3f5a32d3ea360b585614600Tobin Ehlis        lock.unlock();
50884a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyImage(device, image, pAllocator);
50892a0dd15a44bf665c97a3ff6adcbe7fe5853cdf60Tobin Ehlis        lock.lock();
5090405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (image != VK_NULL_HANDLE) {
5091405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyImage(dev_data, image, image_state, obj_struct);
5092405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
50935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
50945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
50955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
50964261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinskistatic bool ValidateMemoryTypes(const layer_data *dev_data, const DEVICE_MEM_INFO *mem_info, const uint32_t memory_type_bits,
5097f634be57d858a71969b3183cd0e322fe1d0ad0fbMike Weiblen                                const char *funcName, UNIQUE_VALIDATION_ERROR_CODE msgCode) {
50983251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
5099de1d2592cdd497642de5b0e6f27ebc439018383bTobin Ehlis    if (((1 << mem_info->alloc_info.memoryTypeIndex) & memory_type_bits) == 0) {
51003251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
51019b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       HandleToUint64(mem_info->mem), __LINE__, msgCode, "MT",
51023251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                       "%s(): MemoryRequirements->memoryTypeBits (0x%X) for this object type are not compatible with the memory "
51033251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                       "type (0x%X) of this memory object 0x%" PRIx64 ". %s",
51049b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       funcName, memory_type_bits, mem_info->alloc_info.memoryTypeIndex, HandleToUint64(mem_info->mem),
51059b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       validation_error_map[msgCode]);
51064261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinski    }
51073251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
51084261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinski}
51094261f1e2c91c90ce040ab36a13c9d92f6e988f10Mark Lobodzinski
5110160335c453ec51cc48bdef78e8befdb3c86ff292Cort Strattonstatic bool PreCallValidateBindBufferMemory(layer_data *dev_data, VkBuffer buffer, BUFFER_STATE *buffer_state, VkDeviceMemory mem,
5111160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                                            VkDeviceSize memoryOffset) {
51129207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    bool skip = false;
51135cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (buffer_state) {
5114160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        std::unique_lock<std::mutex> lock(global_lock);
51159207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        // Track objects tied to memory
51169b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus        uint64_t buffer_handle = HandleToUint64(buffer);
51177a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        skip = ValidateSetMemBinding(dev_data, mem, buffer_handle, kVulkanObjectTypeBuffer, "vkBindBufferMemory()");
51182eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        if (!buffer_state->memory_requirements_checked) {
51192eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            // There's not an explicit requirement in the spec to call vkGetBufferMemoryRequirements() prior to calling
51209207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton            // BindBufferMemory, but it's implied in that memory being bound must conform with VkMemoryRequirements from
51219207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton            // vkGetBufferMemoryRequirements()
51229207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
51239207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            buffer_handle, __LINE__, DRAWSTATE_INVALID_BUFFER, "DS",
51249207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            "vkBindBufferMemory(): Binding memory to buffer 0x%" PRIxLEAST64
51259207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            " but vkGetBufferMemoryRequirements() has not been called on that buffer.",
51269207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            buffer_handle);
51272eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            // Make the call for them so we can verify the state
51282eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            lock.unlock();
51299207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton            dev_data->dispatch_table.GetBufferMemoryRequirements(dev_data->device, buffer, &buffer_state->requirements);
51302eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis            lock.lock();
51312eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        }
513247aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
51330ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        // Validate bound memory range information
51349a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto mem_info = GetMemObjInfo(dev_data, mem);
513557fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        if (mem_info) {
51360ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton            skip |= ValidateInsertBufferMemoryRange(dev_data, buffer, mem_info, memoryOffset, buffer_state->requirements,
51370ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                                    "vkBindBufferMemory()");
51389207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton            skip |= ValidateMemoryTypes(dev_data, mem_info, buffer_state->requirements.memoryTypeBits, "vkBindBufferMemory()",
5139315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                        VALIDATION_ERROR_17000816);
514047aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski        }
514147aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
51422c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves        // Validate memory requirements alignment
514316769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton        if (SafeModulo(memoryOffset, buffer_state->requirements.alignment) != 0) {
5144f60e41965223825191505eebc96491bb52e494a2Cort Stratton            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
5145315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            buffer_handle, __LINE__, VALIDATION_ERROR_17000818, "DS",
51469207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            "vkBindBufferMemory(): memoryOffset is 0x%" PRIxLEAST64
51479207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            " but must be an integer multiple of the "
51489207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            "VkMemoryRequirements::alignment value 0x%" PRIxLEAST64
51499207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                            ", returned from a call to vkGetBufferMemoryRequirements with buffer. %s",
5150315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            memoryOffset, buffer_state->requirements.alignment, validation_error_map[VALIDATION_ERROR_17000818]);
51512c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves        }
5152ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller
5153160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        // Validate memory requirements size
5154160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        if (buffer_state->requirements.size > (mem_info->alloc_info.allocationSize - memoryOffset)) {
5155160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
5156315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            buffer_handle, __LINE__, VALIDATION_ERROR_1700081a, "DS",
5157160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            "vkBindBufferMemory(): memory size minus memoryOffset is 0x%" PRIxLEAST64
5158160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            " but must be at least as large as "
5159160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            "VkMemoryRequirements::size value 0x%" PRIxLEAST64
5160160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            ", returned from a call to vkGetBufferMemoryRequirements with buffer. %s",
5161160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            mem_info->alloc_info.allocationSize - memoryOffset, buffer_state->requirements.size,
5162315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_1700081a]);
5163160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        }
5164160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton
51652c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves        // Validate device limits alignments
5166ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller        static const VkBufferUsageFlagBits usage_list[3] = {
5167ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller            static_cast<VkBufferUsageFlagBits>(VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT),
5168bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT};
5169bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        static const char *memory_type[3] = {"texel", "uniform", "storage"};
5170bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        static const char *offset_name[3] = {"minTexelBufferOffsetAlignment", "minUniformBufferOffsetAlignment",
5171bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                             "minStorageBufferOffsetAlignment"};
5172cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski
51739207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        // TODO:  vk_validation_stats.py cannot abide braces immediately preceding or following a validation error enum
5174cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        // clang-format off
5175315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        static const UNIQUE_VALIDATION_ERROR_CODE msgCode[3] = { VALIDATION_ERROR_17000810, VALIDATION_ERROR_17000812,
5176315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            VALIDATION_ERROR_17000814 };
5177cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        // clang-format on
5178ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller
5179ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller        // Keep this one fresh!
5180ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller        const VkDeviceSize offset_requirement[3] = {
5181ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller            dev_data->phys_dev_properties.properties.limits.minTexelBufferOffsetAlignment,
5182ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller            dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment,
5183bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            dev_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment};
51848718070cf3e206488c168f1e6b9dd06d6880c9bcTobin Ehlis        VkBufferUsageFlags usage = dev_data->bufferMap[buffer].get()->createInfo.usage;
5185ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller
5186ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller        for (int i = 0; i < 3; i++) {
5187ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller            if (usage & usage_list[i]) {
518816769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton                if (SafeModulo(memoryOffset, offset_requirement[i]) != 0) {
51899207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton                    skip |= log_msg(
5190f60e41965223825191505eebc96491bb52e494a2Cort Stratton                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, buffer_handle,
5191cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        __LINE__, msgCode[i], "DS", "vkBindBufferMemory(): %s memoryOffset is 0x%" PRIxLEAST64
5192cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                    " but must be a multiple of "
5193cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                                    "device limit %s 0x%" PRIxLEAST64 ". %s",
5194cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        memory_type[i], memoryOffset, offset_name[i], offset_requirement[i], validation_error_map[msgCode[i]]);
5195ba4316045bf5f1054629bb7c2fced7bae98ed52aMark Mueller                }
51962c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves            }
51972c905c8b5aca814df6c680348145ca48885f9f69Dustin Graves        }
51985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
51999207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    return skip;
52009207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton}
52019207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton
5202160335c453ec51cc48bdef78e8befdb3c86ff292Cort Strattonstatic void PostCallRecordBindBufferMemory(layer_data *dev_data, VkBuffer buffer, BUFFER_STATE *buffer_state, VkDeviceMemory mem,
5203160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                                           VkDeviceSize memoryOffset) {
52049207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    if (buffer_state) {
5205160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        std::unique_lock<std::mutex> lock(global_lock);
52060ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        // Track bound memory range information
52070ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        auto mem_info = GetMemObjInfo(dev_data, mem);
52080ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        if (mem_info) {
52090ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton            InsertBufferMemoryRange(dev_data, buffer, mem_info, memoryOffset, buffer_state->requirements);
52100ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        }
52110ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
5212c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        // Track objects tied to memory
52139b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus        uint64_t buffer_handle = HandleToUint64(buffer);
52147a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        SetMemBinding(dev_data, mem, buffer_handle, kVulkanObjectTypeBuffer, "vkBindBufferMemory()");
5215c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton
52169207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        buffer_state->binding.mem = mem;
52179207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        buffer_state->binding.offset = memoryOffset;
52189207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        buffer_state->binding.size = buffer_state->requirements.size;
52199207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    }
52209207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton}
52219207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton
52229207132ef623d47fcbdfeb9ebc796eade35a2f4cCort StrattonVKAPI_ATTR VkResult VKAPI_CALL BindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
52239207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
52249207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
5225160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton    auto buffer_state = GetBufferState(dev_data, buffer);
5226160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton    bool skip = PreCallValidateBindBufferMemory(dev_data, buffer, buffer_state, mem, memoryOffset);
52279207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton    if (!skip) {
52284a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.BindBufferMemory(device, buffer, mem, memoryOffset);
52299207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        if (result == VK_SUCCESS) {
5230160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton            PostCallRecordBindBufferMemory(dev_data, buffer, buffer_state, mem, memoryOffset);
52319207132ef623d47fcbdfeb9ebc796eade35a2f4cCort Stratton        }
52325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
52335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
52345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
52355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5236bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL GetBufferMemoryRequirements(VkDevice device, VkBuffer buffer,
5237bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                       VkMemoryRequirements *pMemoryRequirements) {
523856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
523915caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    dev_data->dispatch_table.GetBufferMemoryRequirements(device, buffer, pMemoryRequirements);
52409a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto buffer_state = GetBufferState(dev_data, buffer);
524115caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    if (buffer_state) {
524215caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis        buffer_state->requirements = *pMemoryRequirements;
52432eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        buffer_state->memory_requirements_checked = true;
524415caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    }
52455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
52465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5247bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL GetImageMemoryRequirements(VkDevice device, VkImage image, VkMemoryRequirements *pMemoryRequirements) {
524856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
524915caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    dev_data->dispatch_table.GetImageMemoryRequirements(device, image, pMemoryRequirements);
52509a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto image_state = GetImageState(dev_data, image);
525115caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    if (image_state) {
525215caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis        image_state->requirements = *pMemoryRequirements;
52532eda842d84a02b9d5bfb03d6c26c5f7c00e6e8beTobin Ehlis        image_state->memory_requirements_checked = true;
525415caa3e8f88f57bdcc42a3eabb9375e57007e5aaTobin Ehlis    }
52555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
5256593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
5257bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyImageView(VkDevice device, VkImageView imageView, const VkAllocationCallbacks *pAllocator) {
525856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5259f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    // Common data objects used pre & post call
5260f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    IMAGE_VIEW_STATE *image_view_state = nullptr;
5261f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    VK_OBJECT obj_struct;
5262a123662876eebfa844faa65ae3f071d3d77618ebTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
5263f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis    bool skip = PreCallValidateDestroyImageView(dev_data, imageView, &image_view_state, &obj_struct);
5264d85c42a6c1d6ad7a6f684c5bd793aab482b7705cTobin Ehlis    if (!skip) {
5265d85c42a6c1d6ad7a6f684c5bd793aab482b7705cTobin Ehlis        lock.unlock();
52664a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyImageView(device, imageView, pAllocator);
5267f61017735c3291a2665487f2bac310578fc60a68Tobin Ehlis        lock.lock();
5268405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (imageView != VK_NULL_HANDLE) {
5269405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyImageView(dev_data, imageView, image_view_state, obj_struct);
5270405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
5271d85c42a6c1d6ad7a6f684c5bd793aab482b7705cTobin Ehlis    }
52725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
52735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5274bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyShaderModule(VkDevice device, VkShaderModule shaderModule,
5275bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                               const VkAllocationCallbacks *pAllocator) {
527656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5277918c283ac4f8c604b79abd0c8b5706d2a7352a34Chris Forbes
5278b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
527951ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    dev_data->shaderModuleMap.erase(shaderModule);
5280b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
5281918c283ac4f8c604b79abd0c8b5706d2a7352a34Chris Forbes
528251ea774638f432bd8e700ec8291a980f405f429eTobin Ehlis    dev_data->dispatch_table.DestroyShaderModule(device, shaderModule, pAllocator);
52835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
52845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
52854c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic bool PreCallValidateDestroyPipeline(layer_data *dev_data, VkPipeline pipeline, PIPELINE_STATE **pipeline_state,
52868bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis                                           VK_OBJECT *obj_struct) {
528794165f5005d1fa37801d49067fe7751789b89d27Tobin Ehlis    *pipeline_state = getPipelineState(dev_data, pipeline);
52889b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    *obj_struct = {HandleToUint64(pipeline), kVulkanObjectTypePipeline};
5289cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_pipeline) return false;
52908bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    bool skip = false;
52918bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    if (*pipeline_state) {
5292315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *pipeline_state, *obj_struct, VALIDATION_ERROR_25c005fa);
52938bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    }
52948bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    return skip;
52958bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis}
52968bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis
52974c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisstatic void PostCallRecordDestroyPipeline(layer_data *dev_data, VkPipeline pipeline, PIPELINE_STATE *pipeline_state,
52988bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis                                          VK_OBJECT obj_struct) {
52998bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    // Any bound cmd buffers are now invalid
530039c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, pipeline_state->cb_bindings, obj_struct);
53010a136bc9fe42c042857c90a421d0426bd0c029efGabríel Arthúr Pétursson    delete getPipelineState(dev_data, pipeline);
53028bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    dev_data->pipelineMap.erase(pipeline);
53038bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis}
53048bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis
5305bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyPipeline(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks *pAllocator) {
530656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
53074c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    PIPELINE_STATE *pipeline_state = nullptr;
53088bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    VK_OBJECT obj_struct;
5309e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
53108bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis    bool skip = PreCallValidateDestroyPipeline(dev_data, pipeline, &pipeline_state, &obj_struct);
5311f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    if (!skip) {
5312f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis        lock.unlock();
53134a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyPipeline(device, pipeline, pAllocator);
53148bd2ec9a26cca477de2de93304774cdba0af77bcTobin Ehlis        lock.lock();
5315405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (pipeline != VK_NULL_HANDLE) {
5316405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyPipeline(dev_data, pipeline, pipeline_state, obj_struct);
5317405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
5318f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    }
53195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
53205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5321bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyPipelineLayout(VkDevice device, VkPipelineLayout pipelineLayout,
5322bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkAllocationCallbacks *pAllocator) {
532356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5324e28cddb35c63274c13873b9a7060ad43b255c6f1Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
53256792ea7cc0ce5fa64b7bd6c946460608cbda91c7Tobin Ehlis    dev_data->pipelineLayoutMap.erase(pipelineLayout);
5326e28cddb35c63274c13873b9a7060ad43b255c6f1Tobin Ehlis    lock.unlock();
5327e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis
53284a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.DestroyPipelineLayout(device, pipelineLayout, pAllocator);
53295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
53305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5331d31a44af6da568692a73201825459689c9431867Tobin Ehlisstatic bool PreCallValidateDestroySampler(layer_data *dev_data, VkSampler sampler, SAMPLER_STATE **sampler_state,
5332806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis                                          VK_OBJECT *obj_struct) {
53339a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *sampler_state = GetSamplerState(dev_data, sampler);
53349b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    *obj_struct = {HandleToUint64(sampler), kVulkanObjectTypeSampler};
5335cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_sampler) return false;
5336806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    bool skip = false;
5337806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    if (*sampler_state) {
5338315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *sampler_state, *obj_struct, VALIDATION_ERROR_26600874);
5339806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    }
5340806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    return skip;
5341806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis}
5342806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis
5343d31a44af6da568692a73201825459689c9431867Tobin Ehlisstatic void PostCallRecordDestroySampler(layer_data *dev_data, VkSampler sampler, SAMPLER_STATE *sampler_state,
5344806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis                                         VK_OBJECT obj_struct) {
5345806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    // Any bound cmd buffers are now invalid
5346cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (sampler_state) invalidateCommandBuffers(dev_data, sampler_state->cb_bindings, obj_struct);
5347806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    dev_data->samplerMap.erase(sampler);
5348806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis}
5349806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis
5350bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroySampler(VkDevice device, VkSampler sampler, const VkAllocationCallbacks *pAllocator) {
535156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5352d31a44af6da568692a73201825459689c9431867Tobin Ehlis    SAMPLER_STATE *sampler_state = nullptr;
5353806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    VK_OBJECT obj_struct;
535456f8a8f9b7e8c01d76d73be117ebcb66035db6dfTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
5355806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis    bool skip = PreCallValidateDestroySampler(dev_data, sampler, &sampler_state, &obj_struct);
5356f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    if (!skip) {
5357f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis        lock.unlock();
53584a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroySampler(device, sampler, pAllocator);
5359806095ea973371ad4c82bd0c2c58d53cc5557f0bTobin Ehlis        lock.lock();
5360405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (sampler != VK_NULL_HANDLE) {
5361405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroySampler(dev_data, sampler, sampler_state, obj_struct);
5362405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
5363f57cf525e45f3a65e25c2691464d65e29a79ba77Tobin Ehlis    }
53645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
53655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
536679c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlisstatic void PostCallRecordDestroyDescriptorSetLayout(layer_data *dev_data, VkDescriptorSetLayout ds_layout) {
536779c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis    dev_data->descriptorSetLayoutMap.erase(ds_layout);
536879c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis}
536979c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis
5370bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyDescriptorSetLayout(VkDevice device, VkDescriptorSetLayout descriptorSetLayout,
5371bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      const VkAllocationCallbacks *pAllocator) {
537256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
537379c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis    dev_data->dispatch_table.DestroyDescriptorSetLayout(device, descriptorSetLayout, pAllocator);
537479c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
537579c5b660cd51e93e279c1aa001a42801d3bf7a5dTobin Ehlis    PostCallRecordDestroyDescriptorSetLayout(dev_data, descriptorSetLayout);
53765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
53775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5378c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlisstatic bool PreCallValidateDestroyDescriptorPool(layer_data *dev_data, VkDescriptorPool pool,
5379a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis                                                 DESCRIPTOR_POOL_STATE **desc_pool_state, VK_OBJECT *obj_struct) {
53809a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *desc_pool_state = GetDescriptorPoolState(dev_data, pool);
53819b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    *obj_struct = {HandleToUint64(pool), kVulkanObjectTypeDescriptorPool};
5382cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_descriptor_pool) return false;
5383c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    bool skip = false;
5384c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    if (*desc_pool_state) {
5385315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *desc_pool_state, *obj_struct, VALIDATION_ERROR_2440025e);
5386c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    }
5387c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    return skip;
5388c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis}
5389c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis
5390c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlisstatic void PostCallRecordDestroyDescriptorPool(layer_data *dev_data, VkDescriptorPool descriptorPool,
5391a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis                                                DESCRIPTOR_POOL_STATE *desc_pool_state, VK_OBJECT obj_struct) {
5392c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    // Any bound cmd buffers are now invalid
539339c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, desc_pool_state->cb_bindings, obj_struct);
5394c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    // Free sets that were in this pool
5395c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    for (auto ds : desc_pool_state->sets) {
5396c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis        freeDescriptorSet(dev_data, ds);
5397c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    }
5398c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    dev_data->descriptorPoolMap.erase(descriptorPool);
5399ee7e96d032744c1db89cab21362ac8ecad6eec5aGabríel Arthúr Pétursson    delete desc_pool_state;
5400c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis}
5401c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis
5402bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool,
5403bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkAllocationCallbacks *pAllocator) {
540456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5405a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis    DESCRIPTOR_POOL_STATE *desc_pool_state = nullptr;
5406c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    VK_OBJECT obj_struct;
5407c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
5408c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    bool skip = PreCallValidateDestroyDescriptorPool(dev_data, descriptorPool, &desc_pool_state, &obj_struct);
5409c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    if (!skip) {
5410c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis        lock.unlock();
5411c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis        dev_data->dispatch_table.DestroyDescriptorPool(device, descriptorPool, pAllocator);
5412c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis        lock.lock();
5413405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (descriptorPool != VK_NULL_HANDLE) {
5414405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyDescriptorPool(dev_data, descriptorPool, desc_pool_state, obj_struct);
5415405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
5416c656e38f76da254b8b19e653d0945cabb43329bcTobin Ehlis    }
54175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
54183251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski// Verify cmdBuffer in given cb_node is not in global in-flight set, and return skip result
5419bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis//  If this is a secondary command buffer, then make sure its primary is also in-flight
5420bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis//  If primary is not in-flight, then remove secondary from global in-flight set
5421bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis// This function is only valid at a point when cmdBuffer is being reset or freed
5422cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlisstatic bool checkCommandBufferInFlight(layer_data *dev_data, const GLOBAL_CB_NODE *cb_node, const char *action,
5423cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis                                       UNIQUE_VALIDATION_ERROR_CODE error_code) {
54243251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
5425a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes    if (cb_node->in_use.load()) {
5426a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
5427a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes                        HandleToUint64(cb_node->commandBuffer), __LINE__, error_code, "DS",
5428a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes                        "Attempt to %s command buffer (0x%p) which is in use. %s", action, cb_node->commandBuffer,
5429a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes                        validation_error_map[error_code]);
5430bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    }
54313251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
5432bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis}
5433a964cad279f9749cd9ebfc7555247ff3bff26d53Chris Forbes
5434bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis// Iterate over all cmdBuffers in given commandPool and verify that each is not in use
5435cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlisstatic bool checkCommandBuffersInFlight(layer_data *dev_data, COMMAND_POOL_NODE *pPool, const char *action,
5436cdc73d5b6b64942b377db7220cd16b4045f73c9aTobin Ehlis                                        UNIQUE_VALIDATION_ERROR_CODE error_code) {
54373251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
5438a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes    for (auto cmd_buffer : pPool->commandBuffers) {
5439a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes        skip |= checkCommandBufferInFlight(dev_data, GetCBNode(dev_data, cmd_buffer), action, error_code);
5440bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis    }
54413251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
5442bc300ace5ad8d1935d42ee5dbbf36ce6ace4c0e8Tobin Ehlis}
54435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5444bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL FreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount,
5445bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              const VkCommandBuffer *pCommandBuffers) {
544656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
54473251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
5448b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5449c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes
54505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < commandBufferCount; i++) {
54519a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto cb_node = GetCBNode(dev_data, pCommandBuffers[i]);
54525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Delete CB information structure, and remove from commandBufferMap
54539f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        if (cb_node) {
5454315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            skip |= checkCommandBufferInFlight(dev_data, cb_node, "free", VALIDATION_ERROR_2840005e);
5455c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes        }
5456c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes    }
5457c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes
54583251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return;
5459c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes
54609a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pPool = GetCommandPoolNode(dev_data, commandPool);
5461c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes    for (uint32_t i = 0; i < commandBufferCount; i++) {
54629a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto cb_node = GetCBNode(dev_data, pCommandBuffers[i]);
5463c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes        // Delete CB information structure, and remove from commandBufferMap
54649f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        if (cb_node) {
54655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // reset prior to delete for data clean-up
5466a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes            // TODO: fix this, it's insane.
54679f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis            resetCB(dev_data, cb_node->commandBuffer);
54689f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis            dev_data->commandBufferMap.erase(cb_node->commandBuffer);
54699f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis            delete cb_node;
54705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
54715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
54725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Remove commandBuffer reference from commandPoolMap
5473c05d773a018aa47e89841533a6968d9e5b314038Chris Forbes        pPool->commandBuffers.remove(pCommandBuffers[i]);
54745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5475b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
5476e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis
54774a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.FreeCommandBuffers(device, commandPool, commandBufferCount, pCommandBuffers);
54785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
54795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
548089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo *pCreateInfo,
5481bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkAllocationCallbacks *pAllocator, VkCommandPool *pCommandPool) {
548256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
54835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
54844a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateCommandPool(device, pCreateInfo, pAllocator, pCommandPool);
54855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
54865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
5487b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
54885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->commandPoolMap[*pCommandPool].createFlags = pCreateInfo->flags;
54895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->commandPoolMap[*pCommandPool].queueFamilyIndex = pCreateInfo->queueFamilyIndex;
54905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
54915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
54925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
54935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
549489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo *pCreateInfo,
549589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                               const VkAllocationCallbacks *pAllocator, VkQueryPool *pQueryPool) {
549656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
54970c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    bool skip = false;
54980c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    if (pCreateInfo && pCreateInfo->queryType == VK_QUERY_TYPE_PIPELINE_STATISTICS) {
54990c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis        if (!dev_data->enabled_features.pipelineStatisticsQuery) {
55000c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0,
5501315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            __LINE__, VALIDATION_ERROR_11c0062e, "DS",
55020c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis                            "Query pool with type VK_QUERY_TYPE_PIPELINE_STATISTICS created on a device "
55030c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis                            "with VkDeviceCreateInfo.pEnabledFeatures.pipelineStatisticsQuery == VK_FALSE. %s",
5504315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_11c0062e]);
55050c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis        }
55060c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    }
55070c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis
55080c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
55090c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    if (!skip) {
55100c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis        result = dev_data->dispatch_table.CreateQueryPool(device, pCreateInfo, pAllocator, pQueryPool);
55110c45ab93ccfb9d39698ae47d6102d2e308ff476eTobin Ehlis    }
55125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
5513b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
5514eafbf0b68ee6ea6e0bf33f07e0058d00a96efd9aTobin Ehlis        QUERY_POOL_NODE *qp_node = &dev_data->queryPoolMap[*pQueryPool];
5515eafbf0b68ee6ea6e0bf33f07e0058d00a96efd9aTobin Ehlis        qp_node->createInfo = *pCreateInfo;
55165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
55175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
55185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
55195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
55205f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlisstatic bool PreCallValidateDestroyCommandPool(layer_data *dev_data, VkCommandPool pool, COMMAND_POOL_NODE **cp_state) {
55219a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *cp_state = GetCommandPoolNode(dev_data, pool);
5522cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_command_pool) return false;
55235f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    bool skip = false;
55245f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    if (*cp_state) {
55255f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        // Verify that command buffers in pool are complete (not in-flight)
5526315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= checkCommandBuffersInFlight(dev_data, *cp_state, "destroy command pool with", VALIDATION_ERROR_24000052);
55275f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    }
55285f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    return skip;
55295f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis}
55305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
55315f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlisstatic void PostCallRecordDestroyCommandPool(layer_data *dev_data, VkCommandPool pool, COMMAND_POOL_NODE *cp_state) {
55329f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis    // Must remove cmdpool from cmdpoolmap, after removing all cmdbuffers in its list from the commandBufferMap
55335f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    for (auto cb : cp_state->commandBuffers) {
55349a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto cb_node = GetCBNode(dev_data, cb);
55357b34d10b918c1f69e7252174965c6a7a7c35ae05Chris Forbes        clear_cmd_buf_and_mem_references(dev_data, cb_node);
5536d61de0e68063faa169a9a632f811c9c9adec9897Tobin Ehlis        // Remove references to this cb_node prior to delete
5537d61de0e68063faa169a9a632f811c9c9adec9897Tobin Ehlis        // TODO : Need better solution here, resetCB?
55387165385f3a39f1f951f3a6a9a06ed2cce4642b6dMark Lobodzinski        for (auto obj : cb_node->object_bindings) {
55397165385f3a39f1f951f3a6a9a06ed2cce4642b6dMark Lobodzinski            removeCommandBufferBinding(dev_data, &obj, cb_node);
55407165385f3a39f1f951f3a6a9a06ed2cce4642b6dMark Lobodzinski        }
5541d61de0e68063faa169a9a632f811c9c9adec9897Tobin Ehlis        for (auto framebuffer : cb_node->framebuffers) {
55429a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto fb_state = GetFramebufferState(dev_data, framebuffer);
5543cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (fb_state) fb_state->cb_bindings.erase(cb_node);
5544d61de0e68063faa169a9a632f811c9c9adec9897Tobin Ehlis        }
5545cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        dev_data->commandBufferMap.erase(cb);  // Remove this command buffer
5546cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        delete cb_node;                        // delete CB info structure
5547a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes    }
55485f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    dev_data->commandPoolMap.erase(pool);
55495f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis}
5550e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis
55515f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis// Destroy commandPool along with all of the commandBuffers allocated from that pool
55525f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin EhlisVKAPI_ATTR void VKAPI_CALL DestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks *pAllocator) {
555356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
55545f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    COMMAND_POOL_NODE *cp_state = nullptr;
55555f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
55565f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    bool skip = PreCallValidateDestroyCommandPool(dev_data, commandPool, &cp_state);
55575f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    if (!skip) {
55585f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        lock.unlock();
55595f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        dev_data->dispatch_table.DestroyCommandPool(device, commandPool, pAllocator);
55605f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis        lock.lock();
5561405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (commandPool != VK_NULL_HANDLE) {
5562405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyCommandPool(dev_data, commandPool, cp_state);
5563405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
55645f9c0dbd099bd351bc564e0f05170ceeadcc995dTobin Ehlis    }
55655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
55665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5567bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL ResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags) {
556856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
55693251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
5570400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis
55711ec6311a8537f4467db08eacbd762ebaa87e70b0Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
55729a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pPool = GetCommandPoolNode(dev_data, commandPool);
5573315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= checkCommandBuffersInFlight(dev_data, pPool, "reset command pool with", VALIDATION_ERROR_32800050);
55741ec6311a8537f4467db08eacbd762ebaa87e70b0Chris Forbes    lock.unlock();
5575a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes
55763251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
55775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
55784a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.ResetCommandPool(device, commandPool, flags);
55795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
55805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Reset all of the CBs allocated from this pool
55815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
55821ec6311a8537f4467db08eacbd762ebaa87e70b0Chris Forbes        lock.lock();
5583a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes        for (auto cmdBuffer : pPool->commandBuffers) {
5584a01b5eb150981aad061238e64b173d0da8c11140Chris Forbes            resetCB(dev_data, cmdBuffer);
55855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
55861ec6311a8537f4467db08eacbd762ebaa87e70b0Chris Forbes        lock.unlock();
55875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
55885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
55895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
55905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
559189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL ResetFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences) {
559256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
55933251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
5594b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
55955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < fenceCount; ++i) {
55969a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto pFence = GetFenceNode(dev_data, pFences[i]);
5597090da73358f71ba026e2474a822fecf55267d166Chris Forbes        if (pFence && pFence->state == FENCE_INFLIGHT) {
5598315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            skip |=
5599315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
5600315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pFences[i]), __LINE__, VALIDATION_ERROR_32e008c6, "DS", "Fence 0x%" PRIx64 " is in use. %s",
5601315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pFences[i]), validation_error_map[VALIDATION_ERROR_32e008c6]);
56025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
56035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5604b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
5605090da73358f71ba026e2474a822fecf55267d166Chris Forbes
56063251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
5607090da73358f71ba026e2474a822fecf55267d166Chris Forbes
56084a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.ResetFences(device, fenceCount, pFences);
5609090da73358f71ba026e2474a822fecf55267d166Chris Forbes
5610090da73358f71ba026e2474a822fecf55267d166Chris Forbes    if (result == VK_SUCCESS) {
5611090da73358f71ba026e2474a822fecf55267d166Chris Forbes        lock.lock();
5612090da73358f71ba026e2474a822fecf55267d166Chris Forbes        for (uint32_t i = 0; i < fenceCount; ++i) {
56139a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pFence = GetFenceNode(dev_data, pFences[i]);
5614090da73358f71ba026e2474a822fecf55267d166Chris Forbes            if (pFence) {
5615090da73358f71ba026e2474a822fecf55267d166Chris Forbes                pFence->state = FENCE_UNSIGNALED;
5616090da73358f71ba026e2474a822fecf55267d166Chris Forbes            }
5617090da73358f71ba026e2474a822fecf55267d166Chris Forbes        }
5618090da73358f71ba026e2474a822fecf55267d166Chris Forbes        lock.unlock();
5619090da73358f71ba026e2474a822fecf55267d166Chris Forbes    }
5620090da73358f71ba026e2474a822fecf55267d166Chris Forbes
56215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
56225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
56235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5624e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis// For given cb_nodes, invalidate them and track object causing invalidation
56250a4087f99558069e9f6a437ff2dbb5a9c1c22ccaTobin Ehlisvoid invalidateCommandBuffers(const layer_data *dev_data, std::unordered_set<GLOBAL_CB_NODE *> const &cb_nodes, VK_OBJECT obj) {
5626e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis    for (auto cb_node : cb_nodes) {
562739c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis        if (cb_node->state == CB_RECORDING) {
562839c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis            log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
56299b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    HandleToUint64(cb_node->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
5630226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    "Invalidating a command buffer that's currently being recorded: 0x%p.", cb_node->commandBuffer);
563139c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis        }
5632e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis        cb_node->state = CB_INVALID;
5633e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis        cb_node->broken_bindings.push_back(obj);
5634db365f522319df6446b50584277a3bbfee1c1052Chris Forbes
5635db365f522319df6446b50584277a3bbfee1c1052Chris Forbes        // if secondary, then propagate the invalidation to the primaries that will call us.
5636db365f522319df6446b50584277a3bbfee1c1052Chris Forbes        if (cb_node->createInfo.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY) {
5637db365f522319df6446b50584277a3bbfee1c1052Chris Forbes            invalidateCommandBuffers(dev_data, cb_node->linkedCommandBuffers, obj);
5638db365f522319df6446b50584277a3bbfee1c1052Chris Forbes        }
5639e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis    }
5640e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis}
5641e1cc7cf9e8a7808209ecc45df2421f3a494dacccTobin Ehlis
5642c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlisstatic bool PreCallValidateDestroyFramebuffer(layer_data *dev_data, VkFramebuffer framebuffer,
5643c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis                                              FRAMEBUFFER_STATE **framebuffer_state, VK_OBJECT *obj_struct) {
56449a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *framebuffer_state = GetFramebufferState(dev_data, framebuffer);
56459b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    *obj_struct = {HandleToUint64(framebuffer), kVulkanObjectTypeFramebuffer};
5646cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_framebuffer) return false;
5647728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    bool skip = false;
5648728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    if (*framebuffer_state) {
5649315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *framebuffer_state, *obj_struct, VALIDATION_ERROR_250006f8);
5650728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    }
5651728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    return skip;
5652728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis}
5653728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis
5654c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlisstatic void PostCallRecordDestroyFramebuffer(layer_data *dev_data, VkFramebuffer framebuffer, FRAMEBUFFER_STATE *framebuffer_state,
5655728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis                                             VK_OBJECT obj_struct) {
565639c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, framebuffer_state->cb_bindings, obj_struct);
5657728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    dev_data->frameBufferMap.erase(framebuffer);
5658728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis}
5659728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis
5660bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyFramebuffer(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks *pAllocator) {
566156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
5662c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    FRAMEBUFFER_STATE *framebuffer_state = nullptr;
5663728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    VK_OBJECT obj_struct;
5664b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
5665728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    bool skip = PreCallValidateDestroyFramebuffer(dev_data, framebuffer, &framebuffer_state, &obj_struct);
5666728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis    if (!skip) {
5667728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis        lock.unlock();
5668728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis        dev_data->dispatch_table.DestroyFramebuffer(device, framebuffer, pAllocator);
5669728a3e68af2277743cc59185dab7281e96480efeTobin Ehlis        lock.lock();
5670405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (framebuffer != VK_NULL_HANDLE) {
5671405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyFramebuffer(dev_data, framebuffer, framebuffer_state, obj_struct);
5672405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
56735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
56745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
56755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
56760ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlisstatic bool PreCallValidateDestroyRenderPass(layer_data *dev_data, VkRenderPass render_pass, RENDER_PASS_STATE **rp_state,
56770ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis                                             VK_OBJECT *obj_struct) {
56789a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *rp_state = GetRenderPassState(dev_data, render_pass);
56799b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    *obj_struct = {HandleToUint64(render_pass), kVulkanObjectTypeRenderPass};
5680cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.destroy_renderpass) return false;
56810ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    bool skip = false;
56820ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    if (*rp_state) {
5683315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateObjectNotInUse(dev_data, *rp_state, *obj_struct, VALIDATION_ERROR_264006d2);
56840ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    }
56850ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    return skip;
56860ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis}
56870ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis
56880ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlisstatic void PostCallRecordDestroyRenderPass(layer_data *dev_data, VkRenderPass render_pass, RENDER_PASS_STATE *rp_state,
56890ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis                                            VK_OBJECT obj_struct) {
569039c845ed4c066740e9efaed0a00af51be07c67c1Tobin Ehlis    invalidateCommandBuffers(dev_data, rp_state->cb_bindings, obj_struct);
56910ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    dev_data->renderPassMap.erase(render_pass);
56920ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis}
56930ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis
5694bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks *pAllocator) {
569556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
56960ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    RENDER_PASS_STATE *rp_state = nullptr;
56970ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    VK_OBJECT obj_struct;
5698e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
56990ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis    bool skip = PreCallValidateDestroyRenderPass(dev_data, renderPass, &rp_state, &obj_struct);
5700a9fbfe0c622e9fa4b56ddd015ed4c3c409020c2eTobin Ehlis    if (!skip) {
5701a9fbfe0c622e9fa4b56ddd015ed4c3c409020c2eTobin Ehlis        lock.unlock();
57024a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.DestroyRenderPass(device, renderPass, pAllocator);
57030ffd03853dc28123fa113e6cd49264838559ee39Tobin Ehlis        lock.lock();
5704405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (renderPass != VK_NULL_HANDLE) {
5705405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            PostCallRecordDestroyRenderPass(dev_data, renderPass, rp_state, obj_struct);
5706405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
5707a9fbfe0c622e9fa4b56ddd015ed4c3c409020c2eTobin Ehlis    }
57085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
57095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
571089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo,
571189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                            const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer) {
571256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
57133683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    std::unique_lock<std::mutex> lock(global_lock);
57143683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    bool skip = PreCallValidateCreateBuffer(dev_data, pCreateInfo);
57153683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    lock.unlock();
57163683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski
57173683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
57184a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateBuffer(device, pCreateInfo, pAllocator, pBuffer);
57195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
57205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
57213683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski        lock.lock();
57223683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski        PostCallRecordCreateBuffer(dev_data, pCreateInfo, pBuffer);
57233683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski        lock.unlock();
57245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
57255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
57265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
57275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
572889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateBufferView(VkDevice device, const VkBufferViewCreateInfo *pCreateInfo,
572989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                const VkAllocationCallbacks *pAllocator, VkBufferView *pView) {
573056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
57318c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    std::unique_lock<std::mutex> lock(global_lock);
57323251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = PreCallValidateCreateBufferView(dev_data, pCreateInfo);
57338c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    lock.unlock();
57343251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
57354a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateBufferView(device, pCreateInfo, pAllocator, pView);
57365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
57378c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young        lock.lock();
57383683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski        PostCallRecordCreateBufferView(dev_data, pCreateInfo, pView);
57398c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young        lock.unlock();
57405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
57415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
57425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
57435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
57448dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski// Access helper functions for external modules
5745d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinskiconst VkFormatProperties *GetFormatProperties(core_validation::layer_data *device_data, VkFormat format) {
5746d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    VkFormatProperties *format_properties = new VkFormatProperties;
5747d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    instance_layer_data *instance_data =
5748d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski        GetLayerDataPtr(get_dispatch_key(device_data->instance_data->instance), instance_layer_data_map);
5749d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    instance_data->dispatch_table.GetPhysicalDeviceFormatProperties(device_data->physical_device, format, format_properties);
5750d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    return format_properties;
57518dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski}
57528dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski
5753d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinskiconst VkImageFormatProperties *GetImageFormatProperties(core_validation::layer_data *device_data, VkFormat format,
5754d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski                                                        VkImageType image_type, VkImageTiling tiling, VkImageUsageFlags usage,
5755d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski                                                        VkImageCreateFlags flags) {
5756d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    VkImageFormatProperties *image_format_properties = new VkImageFormatProperties;
5757d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    instance_layer_data *instance_data =
5758d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski        GetLayerDataPtr(get_dispatch_key(device_data->instance_data->instance), instance_layer_data_map);
5759d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    instance_data->dispatch_table.GetPhysicalDeviceImageFormatProperties(device_data->physical_device, format, image_type, tiling,
5760d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski                                                                         usage, flags, image_format_properties);
5761d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinski    return image_format_properties;
57628dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski}
57638dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski
57647a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlisconst debug_report_data *GetReportData(const core_validation::layer_data *device_data) { return device_data->report_data; }
57658dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski
57668dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinskiconst VkPhysicalDeviceProperties *GetPhysicalDeviceProperties(core_validation::layer_data *device_data) {
57678dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski    return &device_data->phys_dev_props;
57688dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski}
57698dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski
57708c59133586421be878d393799b30044497f77727Mark Lobodzinskiconst CHECK_DISABLED *GetDisables(core_validation::layer_data *device_data) { return &device_data->instance_data->disabled; }
57718c59133586421be878d393799b30044497f77727Mark Lobodzinski
57728c59133586421be878d393799b30044497f77727Mark Lobodzinskistd::unordered_map<VkImage, std::unique_ptr<IMAGE_STATE>> *GetImageMap(core_validation::layer_data *device_data) {
57738c59133586421be878d393799b30044497f77727Mark Lobodzinski    return &device_data->imageMap;
57748c59133586421be878d393799b30044497f77727Mark Lobodzinski}
57758c59133586421be878d393799b30044497f77727Mark Lobodzinski
57768c59133586421be878d393799b30044497f77727Mark Lobodzinskistd::unordered_map<VkImage, std::vector<ImageSubresourcePair>> *GetImageSubresourceMap(core_validation::layer_data *device_data) {
57778c59133586421be878d393799b30044497f77727Mark Lobodzinski    return &device_data->imageSubresourceMap;
57788c59133586421be878d393799b30044497f77727Mark Lobodzinski}
57798c59133586421be878d393799b30044497f77727Mark Lobodzinski
57808c59133586421be878d393799b30044497f77727Mark Lobodzinskistd::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> *GetImageLayoutMap(layer_data *device_data) {
57818c59133586421be878d393799b30044497f77727Mark Lobodzinski    return &device_data->imageLayoutMap;
57828c59133586421be878d393799b30044497f77727Mark Lobodzinski}
57838c59133586421be878d393799b30044497f77727Mark Lobodzinski
57840db18ab1345f9e10907913b22ea5d57bd48077ebTobin Ehlisstd::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> const *GetImageLayoutMap(layer_data const *device_data) {
57850db18ab1345f9e10907913b22ea5d57bd48077ebTobin Ehlis    return &device_data->imageLayoutMap;
57860db18ab1345f9e10907913b22ea5d57bd48077ebTobin Ehlis}
57870db18ab1345f9e10907913b22ea5d57bd48077ebTobin Ehlis
57883683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinskistd::unordered_map<VkBuffer, std::unique_ptr<BUFFER_STATE>> *GetBufferMap(layer_data *device_data) {
57893683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    return &device_data->bufferMap;
57903683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski}
57913683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski
57923683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinskistd::unordered_map<VkBufferView, std::unique_ptr<BUFFER_VIEW_STATE>> *GetBufferViewMap(layer_data *device_data) {
57933683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski    return &device_data->bufferViewMap;
57943683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski}
57953683836d93195a82dfd2c715ce9d56b030801598Mark Lobodzinski
57961c143ebdb651ea034e0b1f8731cb9f361e2f8b82Mark Lobodzinskistd::unordered_map<VkImageView, std::unique_ptr<IMAGE_VIEW_STATE>> *GetImageViewMap(layer_data *device_data) {
57971c143ebdb651ea034e0b1f8731cb9f361e2f8b82Mark Lobodzinski    return &device_data->imageViewMap;
57981c143ebdb651ea034e0b1f8731cb9f361e2f8b82Mark Lobodzinski}
57991c143ebdb651ea034e0b1f8731cb9f361e2f8b82Mark Lobodzinski
5800d0b59d0aabea9048c518840e762c7a510927c132Mark Lobodzinskiconst PHYS_DEV_PROPERTIES_NODE *GetPhysDevProperties(const layer_data *device_data) {
58016a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    return &device_data->phys_dev_properties;
58026a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski}
58036a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski
58045f3e7c34de87353f38bbcd79e12de8af4a9e7695Mark Lobodzinskiconst VkPhysicalDeviceFeatures *GetEnabledFeatures(const layer_data *device_data) {
58055f3e7c34de87353f38bbcd79e12de8af4a9e7695Mark Lobodzinski    return &device_data->enabled_features;
58065f3e7c34de87353f38bbcd79e12de8af4a9e7695Mark Lobodzinski}
58075f3e7c34de87353f38bbcd79e12de8af4a9e7695Mark Lobodzinski
5808a149f1a0cb39b48b19822c8cf9ef2426cd2251dfMark Lobodzinskiconst DeviceExtensions *GetDeviceExtensions(const layer_data *device_data) { return &device_data->extensions; }
58090e2296e24065d02615ee87561bbb80af414a1ddfMike Schuchardt
581089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo,
581189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                           const VkAllocationCallbacks *pAllocator, VkImage *pImage) {
58128dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
581356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
58148dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski    bool skip = PreCallValidateCreateImage(dev_data, pCreateInfo, pAllocator, pImage);
58158dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski    if (!skip) {
58168dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski        result = dev_data->dispatch_table.CreateImage(device, pCreateInfo, pAllocator, pImage);
58178dea300c362f709ad26886548ea46eb4c315e401Mark Lobodzinski    }
58185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
5819b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
5820920311b6aa5614a545cad59521770d0898a75d65Mark Lobodzinski        PostCallRecordCreateImage(dev_data, pCreateInfo, pImage);
58215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
58225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
58235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
58245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
58258c07a094dc9cc4afb6b62181f341c12b9e969041Mark YoungVKAPI_ATTR VkResult VKAPI_CALL CreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo,
58268c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young                                               const VkAllocationCallbacks *pAllocator, VkImageView *pView) {
582756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
58288c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    std::unique_lock<std::mutex> lock(global_lock);
5829e3effabf8e97cae8e006477806ceaca62e4f2ce7Tobin Ehlis    bool skip = PreCallValidateCreateImageView(dev_data, pCreateInfo);
58308c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young    lock.unlock();
5831cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
58324a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateImageView(device, pCreateInfo, pAllocator, pView);
58335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
58348c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young        lock.lock();
583579fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis        PostCallRecordCreateImageView(dev_data, pCreateInfo, *pView);
58368c07a094dc9cc4afb6b62181f341c12b9e969041Mark Young        lock.unlock();
58375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
5838bb6624cb996175d8945190886a200e720b3871efChris Forbes
58395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
58405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
58415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5842bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateFence(VkDevice device, const VkFenceCreateInfo *pCreateInfo,
5843bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           const VkAllocationCallbacks *pAllocator, VkFence *pFence) {
584456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
58454a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateFence(device, pCreateInfo, pAllocator, pFence);
58465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
5847b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
5848a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        auto &fence_node = dev_data->fenceMap[*pFence];
58498988ad37ea5a054ff2ae3cbe4b767ae6c13cf48bChris Forbes        fence_node.fence = *pFence;
5850a265a8ed3bbb32ade305b1be3148d6001a870b76Tobin Ehlis        fence_node.createInfo = *pCreateInfo;
5851cdb1ea0ff0d966dda02543468377eae93b9e2f8fChris Forbes        fence_node.state = (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) ? FENCE_RETIRED : FENCE_UNSIGNALED;
58525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
58535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
58545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
58555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
58565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis// TODO handle pipeline caches
585789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreatePipelineCache(VkDevice device, const VkPipelineCacheCreateInfo *pCreateInfo,
585889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                   const VkAllocationCallbacks *pAllocator, VkPipelineCache *pPipelineCache) {
585956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
58604a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreatePipelineCache(device, pCreateInfo, pAllocator, pPipelineCache);
58615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
58625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
58635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5864bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyPipelineCache(VkDevice device, VkPipelineCache pipelineCache,
5865bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkAllocationCallbacks *pAllocator) {
586656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
58674a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.DestroyPipelineCache(device, pipelineCache, pAllocator);
58685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
58695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5870bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL GetPipelineCacheData(VkDevice device, VkPipelineCache pipelineCache, size_t *pDataSize,
5871bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                    void *pData) {
587256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
58734a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.GetPipelineCacheData(device, pipelineCache, pDataSize, pData);
58745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
58755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
58765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5877bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL MergePipelineCaches(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount,
5878bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   const VkPipelineCache *pSrcCaches) {
587956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
58804a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.MergePipelineCaches(device, dstCache, srcCacheCount, pSrcCaches);
58815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
58825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
58835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
58843d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis// utility function to set collective state for pipeline
58854c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlisvoid set_pipeline_state(PIPELINE_STATE *pPipe) {
58863d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    // If any attachment used by this pipeline has blendEnable, set top-level blendEnable
58873d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    if (pPipe->graphicsPipelineCI.pColorBlendState) {
58883d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        for (size_t i = 0; i < pPipe->attachments.size(); ++i) {
58893d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis            if (VK_TRUE == pPipe->attachments[i].blendEnable) {
58903d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                if (((pPipe->attachments[i].dstAlphaBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
58913d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                     (pPipe->attachments[i].dstAlphaBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
58923d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                    ((pPipe->attachments[i].dstColorBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
58933d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                     (pPipe->attachments[i].dstColorBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
58943d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                    ((pPipe->attachments[i].srcAlphaBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
58953d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                     (pPipe->attachments[i].srcAlphaBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
58963d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                    ((pPipe->attachments[i].srcColorBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
58973d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                     (pPipe->attachments[i].srcColorBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA))) {
58983d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                    pPipe->blendConstantsEnabled = true;
58993d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis                }
59003d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis            }
59013d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        }
59023d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis    }
59033d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis}
59043d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis
5905daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinskibool validate_dual_src_blend_feature(layer_data *device_data, PIPELINE_STATE *pipe_state) {
5906daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski    bool skip = false;
5907daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski    if (pipe_state->graphicsPipelineCI.pColorBlendState) {
5908daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski        for (size_t i = 0; i < pipe_state->attachments.size(); ++i) {
5909daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski            if (!device_data->enabled_features.dualSrcBlend) {
5910daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                if ((pipe_state->attachments[i].dstAlphaBlendFactor == VK_BLEND_FACTOR_SRC1_COLOR) ||
5911daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    (pipe_state->attachments[i].dstAlphaBlendFactor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR) ||
5912daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    (pipe_state->attachments[i].dstAlphaBlendFactor == VK_BLEND_FACTOR_SRC1_ALPHA) ||
5913daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    (pipe_state->attachments[i].dstAlphaBlendFactor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA) ||
5914daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    (pipe_state->attachments[i].srcAlphaBlendFactor == VK_BLEND_FACTOR_SRC1_COLOR) ||
5915daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    (pipe_state->attachments[i].srcAlphaBlendFactor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR) ||
5916daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    (pipe_state->attachments[i].srcAlphaBlendFactor == VK_BLEND_FACTOR_SRC1_ALPHA) ||
5917daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    (pipe_state->attachments[i].srcAlphaBlendFactor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA)) {
5918daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                    skip |=
5919daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                        log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
59209b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pipe_state->pipeline), __LINE__, DRAWSTATE_INVALID_FEATURE, "DS",
5921daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                                "CmdBindPipeline: vkPipeline (0x%" PRIxLEAST64 ") attachment[" PRINTF_SIZE_T_SPECIFIER
5922daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                                "] has a dual-source blend factor but this device feature is not enabled.",
59239b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pipe_state->pipeline), i);
5924daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski                }
5925daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski            }
5926daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski        }
5927daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski    }
5928daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski    return skip;
5929daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski}
5930daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski
593148b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinskistatic bool PreCallCreateGraphicsPipelines(layer_data *device_data, uint32_t count,
593248b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski                                           const VkGraphicsPipelineCreateInfo *create_infos, vector<PIPELINE_STATE *> &pipe_state) {
593348b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski    bool skip = false;
5934bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    instance_layer_data *instance_data =
593556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis        GetLayerDataPtr(get_dispatch_key(device_data->instance_data->instance), instance_layer_data_map);
593648b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski
593748b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski    for (uint32_t i = 0; i < count; i++) {
593848b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski        skip |= verifyPipelineCreateState(device_data, pipe_state, i);
593978b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski        if (create_infos[i].pVertexInputState != NULL) {
594078b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski            for (uint32_t j = 0; j < create_infos[i].pVertexInputState->vertexAttributeDescriptionCount; j++) {
594178b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                VkFormat format = create_infos[i].pVertexInputState->pVertexAttributeDescriptions[j].format;
594278b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                // Internal call to get format info.  Still goes through layers, could potentially go directly to ICD.
594378b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                VkFormatProperties properties;
594478b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                instance_data->dispatch_table.GetPhysicalDeviceFormatProperties(device_data->physical_device, format, &properties);
594578b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                if ((properties.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT) == 0) {
594678b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                    skip |= log_msg(
594778b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                        device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
5948315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        __LINE__, VALIDATION_ERROR_14a004de, "IMAGE",
594978b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                        "vkCreateGraphicsPipelines: pCreateInfo[%d].pVertexInputState->vertexAttributeDescriptions[%d].format "
595078b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                        "(%s) is not a supported vertex buffer format. %s",
5951315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        i, j, string_VkFormat(format), validation_error_map[VALIDATION_ERROR_14a004de]);
595278b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski                }
595378b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski            }
595478b4bdd8b67f4832a05110431ba3c1ae794391d8Mark Lobodzinski        }
595548b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski    }
595648b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski    return skip;
595748b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski}
595848b8ad74fa1a9e39463afce0cb8376c3e0b691a8Mark Lobodzinski
5959bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
5960bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                       const VkGraphicsPipelineCreateInfo *pCreateInfos,
5961bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                       const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) {
59625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO What to do with pipelineCache?
59635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // The order of operations here is a little convoluted but gets the job done
59644c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    //  1. Pipeline create state is first shadowed into PIPELINE_STATE struct
59655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    //  2. Create state is then validated (which uses flags setup during shadowing)
59665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    //  3. If everything looks good, we'll then create the pipeline and add NODE to pipelineMap
596742486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski    bool skip = false;
59685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO : Improve this data struct w/ unique_ptrs so cleanup below is automatic
596942486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski    vector<PIPELINE_STATE *> pipe_state(count);
597056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
59715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
59725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t i = 0;
5973b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
59745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
59755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (i = 0; i < count; i++) {
597642486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski        pipe_state[i] = new PIPELINE_STATE;
597742486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski        pipe_state[i]->initGraphicsPipeline(&pCreateInfos[i]);
59789a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        pipe_state[i]->render_pass_ci.initialize(GetRenderPassState(dev_data, pCreateInfos[i].renderPass)->createInfo.ptr());
597942486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski        pipe_state[i]->pipeline_layout = *getPipelineLayout(dev_data, pCreateInfos[i].layout);
59805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
598142486a20f07b16f0c5361cdc00fd789b07b1989aMark Lobodzinski    skip |= PreCallCreateGraphicsPipelines(dev_data, count, pCreateInfos, pipe_state);
59825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
5983c70226063be6148056ceeccf835175a1fd59f24fChris Forbes    if (skip) {
5984c70226063be6148056ceeccf835175a1fd59f24fChris Forbes        for (i = 0; i < count; i++) {
5985c70226063be6148056ceeccf835175a1fd59f24fChris Forbes            delete pipe_state[i];
59861ab616b32d4e5b7d62d4a8c41b0c03ea335ab845Chris Forbes            pPipelines[i] = VK_NULL_HANDLE;
5987c70226063be6148056ceeccf835175a1fd59f24fChris Forbes        }
59887a456d188475c23b566334be45dc0489b2789653Chris Forbes        return VK_ERROR_VALIDATION_FAILED_EXT;
59897a456d188475c23b566334be45dc0489b2789653Chris Forbes    }
59907a456d188475c23b566334be45dc0489b2789653Chris Forbes
59917a456d188475c23b566334be45dc0489b2789653Chris Forbes    lock.unlock();
5992bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result =
5993bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        dev_data->dispatch_table.CreateGraphicsPipelines(device, pipelineCache, count, pCreateInfos, pAllocator, pPipelines);
59947a456d188475c23b566334be45dc0489b2789653Chris Forbes    lock.lock();
59957a456d188475c23b566334be45dc0489b2789653Chris Forbes    for (i = 0; i < count; i++) {
599661943a7503bc8594338f3364ef42f1d863486c04Chris Forbes        if (pPipelines[i] == VK_NULL_HANDLE) {
599761943a7503bc8594338f3364ef42f1d863486c04Chris Forbes            delete pipe_state[i];
5998bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        } else {
599961943a7503bc8594338f3364ef42f1d863486c04Chris Forbes            pipe_state[i]->pipeline = pPipelines[i];
600061943a7503bc8594338f3364ef42f1d863486c04Chris Forbes            dev_data->pipelineMap[pipe_state[i]->pipeline] = pipe_state[i];
600161943a7503bc8594338f3364ef42f1d863486c04Chris Forbes        }
60025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6003c70226063be6148056ceeccf835175a1fd59f24fChris Forbes
60045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
60055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
60065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6007bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
6008bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      const VkComputePipelineCreateInfo *pCreateInfos,
6009bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) {
60100108a1af0b7c6949846e9d71d00bbfb322b6f7caChris Forbes    bool skip = false;
60115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
60125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // TODO : Improve this data struct w/ unique_ptrs so cleanup below is automatic
60134c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis    vector<PIPELINE_STATE *> pPipeState(count);
601456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
60155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
60165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t i = 0;
6017b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
60185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (i = 0; i < count; i++) {
60195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // TODO: Verify compute stage bits
60205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
60215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Create and initialize internal tracking data structure
60224c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis        pPipeState[i] = new PIPELINE_STATE;
60234c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis        pPipeState[i]->initComputePipeline(&pCreateInfos[i]);
6024c2a5a36d03bbe52f5854a5884346e4a84115e259Tobin Ehlis        pPipeState[i]->pipeline_layout = *getPipelineLayout(dev_data, pCreateInfos[i].layout);
60255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
60265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // TODO: Add Compute Pipeline Verification
6027e446ad08318228362ef35d73e7a0636075cb3636Chris Forbes        skip |= validate_compute_pipeline(dev_data, pPipeState[i]);
60280108a1af0b7c6949846e9d71d00bbfb322b6f7caChris Forbes        // skip |= verifyPipelineCreateState(dev_data, pPipeState[i]);
60295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
60305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
60317a456d188475c23b566334be45dc0489b2789653Chris Forbes    if (skip) {
60325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (i = 0; i < count; i++) {
60335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Clean up any locally allocated data structures
60344c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis            delete pPipeState[i];
6035fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes            pPipelines[i] = VK_NULL_HANDLE;
60365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
60375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return VK_ERROR_VALIDATION_FAILED_EXT;
60385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
60397a456d188475c23b566334be45dc0489b2789653Chris Forbes
60407a456d188475c23b566334be45dc0489b2789653Chris Forbes    lock.unlock();
6041bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result =
6042bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        dev_data->dispatch_table.CreateComputePipelines(device, pipelineCache, count, pCreateInfos, pAllocator, pPipelines);
60437a456d188475c23b566334be45dc0489b2789653Chris Forbes    lock.lock();
60447a456d188475c23b566334be45dc0489b2789653Chris Forbes    for (i = 0; i < count; i++) {
6045fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes        if (pPipelines[i] == VK_NULL_HANDLE) {
6046fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes            delete pPipeState[i];
6047bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        } else {
6048fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes            pPipeState[i]->pipeline = pPipelines[i];
6049fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes            dev_data->pipelineMap[pPipeState[i]->pipeline] = pPipeState[i];
6050fcf67c021fdfcbeb12fb04daa9a69ecd7d376c5cChris Forbes        }
60517a456d188475c23b566334be45dc0489b2789653Chris Forbes    }
60527a456d188475c23b566334be45dc0489b2789653Chris Forbes
60535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
60545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
60555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
605689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateSampler(VkDevice device, const VkSamplerCreateInfo *pCreateInfo,
605789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                             const VkAllocationCallbacks *pAllocator, VkSampler *pSampler) {
605856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
60594a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateSampler(device, pCreateInfo, pAllocator, pSampler);
60605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6061b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
6062d31a44af6da568692a73201825459689c9431867Tobin Ehlis        dev_data->samplerMap[*pSampler] = unique_ptr<SAMPLER_STATE>(new SAMPLER_STATE(pSampler, pCreateInfo));
60635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
60645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
60655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
60665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
60670c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlisstatic bool PreCallValidateCreateDescriptorSetLayout(layer_data *dev_data, const VkDescriptorSetLayoutCreateInfo *create_info) {
6068cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.create_descriptor_set_layout) return false;
60690c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    return cvdescriptorset::DescriptorSetLayout::ValidateCreateInfo(dev_data->report_data, create_info);
60700c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis}
60710c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis
60720c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlisstatic void PostCallRecordCreateDescriptorSetLayout(layer_data *dev_data, const VkDescriptorSetLayoutCreateInfo *create_info,
60730c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis                                                    VkDescriptorSetLayout set_layout) {
6074c8bee427d7a8ed0ccec899fbf47134d582dcafbdGabríel Arthúr Pétursson    dev_data->descriptorSetLayoutMap[set_layout] = std::unique_ptr<cvdescriptorset::DescriptorSetLayout>(
6075c8bee427d7a8ed0ccec899fbf47134d582dcafbdGabríel Arthúr Pétursson        new cvdescriptorset::DescriptorSetLayout(create_info, set_layout));
60760c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis}
60770c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis
6078bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
6079bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                         const VkAllocationCallbacks *pAllocator,
6080bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                         VkDescriptorSetLayout *pSetLayout) {
608156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
60820c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
60830c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
60840c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    bool skip = PreCallValidateCreateDescriptorSetLayout(dev_data, pCreateInfo);
60850c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis    if (!skip) {
60860c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis        lock.unlock();
60870c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis        result = dev_data->dispatch_table.CreateDescriptorSetLayout(device, pCreateInfo, pAllocator, pSetLayout);
60880c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis        if (VK_SUCCESS == result) {
60890c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis            lock.lock();
60900c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis            PostCallRecordCreateDescriptorSetLayout(dev_data, pCreateInfo, *pSetLayout);
60910c347fc6b08172b778c259e1a1219a2403495d48Tobin Ehlis        }
60925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
60935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
60945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
60955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
60969e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz// Used by CreatePipelineLayout and CmdPushConstants.
60979e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz// Note that the index argument is optional and only used by CreatePipelineLayout.
60989e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultzstatic bool validatePushConstantRange(const layer_data *dev_data, const uint32_t offset, const uint32_t size,
60999e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz                                      const char *caller_name, uint32_t index = 0) {
6100cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.push_constant_range) return false;
61019e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    uint32_t const maxPushConstantsSize = dev_data->phys_dev_properties.properties.limits.maxPushConstantsSize;
61023251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
61039e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // Check that offset + size don't exceed the max.
61049e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // Prevent arithetic overflow here by avoiding addition and testing in this order.
61059e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    if ((offset >= maxPushConstantsSize) || (size > maxPushConstantsSize - offset)) {
61069e24d8153ab63bc3ac08b5a1517c203930b5de91Karl 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.
61079e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        if (0 == strcmp(caller_name, "vkCreatePipelineLayout()")) {
6108e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis            if (offset >= maxPushConstantsSize) {
61093251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6110315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                __LINE__, VALIDATION_ERROR_11a0024c, "DS",
61113251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "%s call has push constants index %u with offset %u that "
61123251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "exceeds this device's maxPushConstantSize of %u. %s",
6113315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                caller_name, index, offset, maxPushConstantsSize, validation_error_map[VALIDATION_ERROR_11a0024c]);
6114e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis            }
6115e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis            if (size > maxPushConstantsSize - offset) {
6116315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6117315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                __LINE__, VALIDATION_ERROR_11a00254, "DS",
6118315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                "%s call has push constants index %u with offset %u and size %u that "
6119315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                "exceeds this device's maxPushConstantSize of %u. %s",
6120315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                caller_name, index, offset, size, maxPushConstantsSize,
6121315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                validation_error_map[VALIDATION_ERROR_11a00254]);
6122e420dd92dcfc04f279e98796a49ee26b2c3ddafeTobin Ehlis            }
61239e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else if (0 == strcmp(caller_name, "vkCmdPushConstants()")) {
61244527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            if (offset >= maxPushConstantsSize) {
61253251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6126315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                __LINE__, VALIDATION_ERROR_1bc002e4, "DS",
61273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "%s call has push constants index %u with offset %u that "
61283251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "exceeds this device's maxPushConstantSize of %u. %s",
6129315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                caller_name, index, offset, maxPushConstantsSize, validation_error_map[VALIDATION_ERROR_1bc002e4]);
61304527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            }
61314527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            if (size > maxPushConstantsSize - offset) {
6132315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6133315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                __LINE__, VALIDATION_ERROR_1bc002e6, "DS",
6134315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                "%s call has push constants index %u with offset %u and size %u that "
6135315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                "exceeds this device's maxPushConstantSize of %u. %s",
6136315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                caller_name, index, offset, size, maxPushConstantsSize,
6137315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                validation_error_map[VALIDATION_ERROR_1bc002e6]);
61384527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            }
61399e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else {
61403251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
61413251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            __LINE__, DRAWSTATE_INTERNAL_ERROR, "DS", "%s caller not supported.", caller_name);
61429e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
61439e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    }
61449e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // size needs to be non-zero and a multiple of 4.
61459e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    if ((size == 0) || ((size & 0x3) != 0)) {
61469e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        if (0 == strcmp(caller_name, "vkCreatePipelineLayout()")) {
6147891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis            if (size == 0) {
61483251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6149315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                __LINE__, VALIDATION_ERROR_11a00250, "DS",
61503251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "%s call has push constants index %u with "
61513251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "size %u. Size must be greater than zero. %s",
6152315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                caller_name, index, size, validation_error_map[VALIDATION_ERROR_11a00250]);
6153891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis            }
6154891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis            if (size & 0x3) {
61553251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6156315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                __LINE__, VALIDATION_ERROR_11a00252, "DS",
61573251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "%s call has push constants index %u with "
61583251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "size %u. Size must be a multiple of 4. %s",
6159315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                caller_name, index, size, validation_error_map[VALIDATION_ERROR_11a00252]);
6160891f13be101e95697e5af9503f06da38b0c48f79Tobin Ehlis            }
61619e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else if (0 == strcmp(caller_name, "vkCmdPushConstants()")) {
61624527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            if (size == 0) {
61633251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6164315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                __LINE__, VALIDATION_ERROR_1bc2c21b, "DS",
61653251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "%s call has push constants index %u with "
61663251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "size %u. Size must be greater than zero. %s",
6167315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                caller_name, index, size, validation_error_map[VALIDATION_ERROR_1bc2c21b]);
61684527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            }
61694527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            if (size & 0x3) {
61703251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6171315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                __LINE__, VALIDATION_ERROR_1bc002e2, "DS",
61723251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "%s call has push constants index %u with "
61733251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "size %u. Size must be a multiple of 4. %s",
6174315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                caller_name, index, size, validation_error_map[VALIDATION_ERROR_1bc002e2]);
61754527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            }
61769e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else {
61773251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
61783251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            __LINE__, DRAWSTATE_INTERNAL_ERROR, "DS", "%s caller not supported.", caller_name);
61799e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
61809e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    }
61819e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // offset needs to be a multiple of 4.
61829e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    if ((offset & 0x3) != 0) {
61839e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        if (0 == strcmp(caller_name, "vkCreatePipelineLayout()")) {
61843251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6185315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            __LINE__, VALIDATION_ERROR_11a0024e, "DS",
61863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "%s call has push constants index %u with "
61873251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "offset %u. Offset must be a multiple of 4. %s",
6188315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            caller_name, index, offset, validation_error_map[VALIDATION_ERROR_11a0024e]);
61899e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else if (0 == strcmp(caller_name, "vkCmdPushConstants()")) {
61903251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6191315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            __LINE__, VALIDATION_ERROR_1bc002e0, "DS",
61923251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "%s call has push constants with "
61933251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "offset %u. Offset must be a multiple of 4. %s",
6194315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            caller_name, offset, validation_error_map[VALIDATION_ERROR_1bc002e0]);
61959e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        } else {
61963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
61973251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            __LINE__, DRAWSTATE_INTERNAL_ERROR, "DS", "%s caller not supported.", caller_name);
61989e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
61995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
62003251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
62015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
62025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6203bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo *pCreateInfo,
620489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                    const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout) {
62053251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
620656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
6207bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz    // TODO : Add checks for VALIDATION_ERRORS 865-870
62089e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    // Push Constant Range checks
620907a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz    uint32_t i, j;
62105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
62113251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= validatePushConstantRange(dev_data, pCreateInfo->pPushConstantRanges[i].offset,
62123251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                          pCreateInfo->pPushConstantRanges[i].size, "vkCreatePipelineLayout()", i);
62139e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        if (0 == pCreateInfo->pPushConstantRanges[i].stageFlags) {
62143251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6215315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            __LINE__, VALIDATION_ERROR_11a2dc03, "DS", "vkCreatePipelineLayout() call has no stageFlags set. %s",
6216315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_11a2dc03]);
62179e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
62189e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    }
62193251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
622007a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz
6221bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl 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.
622207a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz    for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
622307a398f7c8da45c8286cba4ef33239646ee87dc9Karl Schultz        for (j = i + 1; j < pCreateInfo->pushConstantRangeCount; ++j) {
6224bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz            if (0 != (pCreateInfo->pPushConstantRanges[i].stageFlags & pCreateInfo->pPushConstantRanges[j].stageFlags)) {
62253251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
6226315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                __LINE__, VALIDATION_ERROR_0fe00248, "DS",
62273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "vkCreatePipelineLayout() Duplicate stage flags found in ranges %d and %d. %s", i, j,
6228315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                validation_error_map[VALIDATION_ERROR_0fe00248]);
62299e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz            }
62305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
62315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6232f73b2046273413ea1338dd714d67c39f8e0fa09eChris Forbes
62334a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreatePipelineLayout(device, pCreateInfo, pAllocator, pPipelineLayout);
62345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6235b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
62365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        PIPELINE_LAYOUT_NODE &plNode = dev_data->pipelineLayoutMap[*pPipelineLayout];
623769b71d9c89447ec87d823669ee9edbfc58af174aTobin Ehlis        plNode.layout = *pPipelineLayout;
6238416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis        plNode.set_layouts.resize(pCreateInfo->setLayoutCount);
62395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (i = 0; i < pCreateInfo->setLayoutCount; ++i) {
62409a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            plNode.set_layouts[i] = GetDescriptorSetLayout(dev_data, pCreateInfo->pSetLayouts[i]);
62415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6242416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis        plNode.push_constant_ranges.resize(pCreateInfo->pushConstantRangeCount);
62435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
6244416bfef833408786b4a17f725b0ed6480bc65120Tobin Ehlis            plNode.push_constant_ranges[i] = pCreateInfo->pPushConstantRanges[i];
62455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
62465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
62475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
62485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
62495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6250bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateDescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo *pCreateInfo,
6251bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                    const VkAllocationCallbacks *pAllocator, VkDescriptorPool *pDescriptorPool) {
625256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
62534a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateDescriptorPool(device, pCreateInfo, pAllocator, pDescriptorPool);
62545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6255a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis        DESCRIPTOR_POOL_STATE *pNewNode = new DESCRIPTOR_POOL_STATE(*pDescriptorPool, pCreateInfo);
62565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (NULL == pNewNode) {
62575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
62589b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(*pDescriptorPool), __LINE__, DRAWSTATE_OUT_OF_MEMORY, "DS",
6259a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis                        "Out of memory while attempting to allocate DESCRIPTOR_POOL_STATE in vkCreateDescriptorPool()"))
62605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                return VK_ERROR_VALIDATION_FAILED_EXT;
62615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
6262b9e992386a44404152747d66817a733aa127e281Jeremy Hayes            std::lock_guard<std::mutex> lock(global_lock);
62635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->descriptorPoolMap[*pDescriptorPool] = pNewNode;
62645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
62655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
62665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Need to do anything if pool create fails?
62675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
62685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
62695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
62705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6271bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL ResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool,
6272bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   VkDescriptorPoolResetFlags flags) {
6273315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    // TODO : Add checks for VALIDATION_ERROR_32a00272
627456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
62754a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.ResetDescriptorPool(device, descriptorPool, flags);
62765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6277b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
62785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        clearDescriptorPool(dev_data, device, descriptorPool, flags);
62795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
62805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
62815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
62822c4e180a4442f968b44f3d5136f7ffda706f6428Chris Forbes// Ensure the pool contains enough descriptors and descriptor sets to satisfy
6283789832b514862c7a7b5b847eeb8e7cacb733b77bTobin Ehlis// an allocation request. Fills common_data with the total number of descriptors of each type required,
6284789832b514862c7a7b5b847eeb8e7cacb733b77bTobin Ehlis// as well as DescriptorSetLayout ptrs used for later update.
62857f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlisstatic bool PreCallValidateAllocateDescriptorSets(layer_data *dev_data, const VkDescriptorSetAllocateInfo *pAllocateInfo,
62867f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis                                                  cvdescriptorset::AllocateDescriptorSetsData *common_data) {
62877a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    // Always update common data
62887a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    cvdescriptorset::UpdateAllocateDescriptorSetsData(dev_data, pAllocateInfo, common_data);
6289cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.allocate_descriptor_sets) return false;
62907e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlis    // All state checks for AllocateDescriptorSets is done in single function
62917a7c05af97a73fc6d4917ddda909f119583ff9fcTobin Ehlis    return cvdescriptorset::ValidateAllocateDescriptorSets(dev_data, pAllocateInfo, common_data);
62927e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlis}
62937e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlis// Allocation state was good and call down chain was made so update state based on allocating descriptor sets
62947e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlisstatic void PostCallRecordAllocateDescriptorSets(layer_data *dev_data, const VkDescriptorSetAllocateInfo *pAllocateInfo,
62957f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis                                                 VkDescriptorSet *pDescriptorSets,
62967f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis                                                 const cvdescriptorset::AllocateDescriptorSetsData *common_data) {
62977e73e5c6b3020b96a821985f73012f2af0f1b992Tobin Ehlis    // All the updates are contained in a single cvdescriptorset function
62982c59c1d90b22aa759d785e4233e468616990ff92Tobin Ehlis    cvdescriptorset::PerformAllocateDescriptorSets(pAllocateInfo, pDescriptorSets, common_data, &dev_data->descriptorPoolMap,
6299b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis                                                   &dev_data->setMap, dev_data);
63002c4e180a4442f968b44f3d5136f7ffda706f6428Chris Forbes}
63012c4e180a4442f968b44f3d5136f7ffda706f6428Chris Forbes
6302bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL AllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo,
6303bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      VkDescriptorSet *pDescriptorSets) {
630456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
6305b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
63067f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis    cvdescriptorset::AllocateDescriptorSetsData common_data(pAllocateInfo->descriptorSetCount);
63073251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = PreCallValidateAllocateDescriptorSets(dev_data, pAllocateInfo, &common_data);
6308b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
6309d173e0daab123373ce75105f2a908f6ae7cef6abChris Forbes
63103251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
6311d173e0daab123373ce75105f2a908f6ae7cef6abChris Forbes
63124a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.AllocateDescriptorSets(device, pAllocateInfo, pDescriptorSets);
63136511ce241f7f210211e0c0e882f3c14889071f4dChris Forbes
63145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6315b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
63167f61868b44f1da1dfa6a4ff726020411db92ce0dTobin Ehlis        PostCallRecordAllocateDescriptorSets(dev_data, pAllocateInfo, pDescriptorSets, &common_data);
6317b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
63185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
63195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
63205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
6321cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis// Verify state before freeing DescriptorSets
6322cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlisstatic bool PreCallValidateFreeDescriptorSets(const layer_data *dev_data, VkDescriptorPool pool, uint32_t count,
6323cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis                                              const VkDescriptorSet *descriptor_sets) {
6324cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.free_descriptor_sets) return false;
63253251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
6326cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    // First make sure sets being destroyed are not currently in-use
6327405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour    for (uint32_t i = 0; i < count; ++i) {
6328405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (descriptor_sets[i] != VK_NULL_HANDLE) {
63293251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= validateIdleDescriptorSet(dev_data, descriptor_sets[i], "vkFreeDescriptorSets");
6330405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
6331405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour    }
6332cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis
63339a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DESCRIPTOR_POOL_STATE *pool_state = GetDescriptorPoolState(dev_data, pool);
6334a21f0d8ac8389dc4e23749efc02d82a7ec1eaee3Tobin Ehlis    if (pool_state && !(VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT & pool_state->createInfo.flags)) {
6335cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis        // Can't Free from a NON_FREE pool
63363251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
6337315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pool), __LINE__, VALIDATION_ERROR_28600270, "DS",
63383251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "It is invalid to call vkFreeDescriptorSets() with a pool created without setting "
63393251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT. %s",
6340315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_28600270]);
6341cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    }
63423251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
6343cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis}
6344cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis// Sets have been removed from the pool so update underlying state
6345cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlisstatic void PostCallRecordFreeDescriptorSets(layer_data *dev_data, VkDescriptorPool pool, uint32_t count,
6346cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis                                             const VkDescriptorSet *descriptor_sets) {
63479a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DESCRIPTOR_POOL_STATE *pool_state = GetDescriptorPoolState(dev_data, pool);
6348cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    // Update available descriptor sets in pool
6349cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    pool_state->availableSets += count;
6350cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis
6351cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    // For each freed descriptor add its resources back into the pool as available and remove from pool and setMap
6352cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    for (uint32_t i = 0; i < count; ++i) {
6353405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        if (descriptor_sets[i] != VK_NULL_HANDLE) {
6354405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            auto descriptor_set = dev_data->setMap[descriptor_sets[i]];
6355405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            uint32_t type_index = 0, descriptor_count = 0;
6356405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            for (uint32_t j = 0; j < descriptor_set->GetBindingCount(); ++j) {
6357405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour                type_index = static_cast<uint32_t>(descriptor_set->GetTypeFromIndex(j));
6358405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour                descriptor_count = descriptor_set->GetDescriptorCountFromIndex(j);
6359405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour                pool_state->availableDescriptorTypeCount[type_index] += descriptor_count;
6360405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            }
6361405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            freeDescriptorSet(dev_data, descriptor_set);
6362405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour            pool_state->sets.erase(descriptor_set);
6363405404ef7f928520a56949bcc4c62f6a337514a9Tony Barbour        }
6364cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis    }
6365cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis}
63665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6367bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL FreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t count,
6368bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                  const VkDescriptorSet *pDescriptorSets) {
636956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
63705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Make sure that no sets being destroyed are in-flight
6371b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
63723251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = PreCallValidateFreeDescriptorSets(dev_data, descriptorPool, count, pDescriptorSets);
6373b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
6374e1a3be272f365a7d75f9cc1338d2eebafbf1e6cdTobin Ehlis
63753251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
63764a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.FreeDescriptorSets(device, descriptorPool, count, pDescriptorSets);
63775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6378b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
6379cd53549dd5a597894f308b4bb993c02ae30817d6Tobin Ehlis        PostCallRecordFreeDescriptorSets(dev_data, descriptorPool, count, pDescriptorSets);
6380b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
63815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
63825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
63835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
63846b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis// TODO : This is a Proof-of-concept for core validation architecture
63856b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis//  Really we'll want to break out these functions to separate files but
63866b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis//  keeping it all together here to prove out design
63876b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis// PreCallValidate* handles validating all of the state prior to calling down chain to UpdateDescriptorSets()
63886b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlisstatic bool PreCallValidateUpdateDescriptorSets(layer_data *dev_data, uint32_t descriptorWriteCount,
63896b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                                const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
63906b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                                const VkCopyDescriptorSet *pDescriptorCopies) {
6391cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (dev_data->instance_data->disabled.update_descriptor_sets) return false;
63926b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // First thing to do is perform map look-ups.
63936b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // NOTE : UpdateDescriptorSets is somewhat unique in that it's operating on a number of DescriptorSets
63946b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    //  so we can't just do a single map look-up up-front, but do them individually in functions below
63956b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis
63966b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // Now make call(s) that validate state, but don't perform state updates in this function
63976b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // Note, here DescriptorSets is unique in that we don't yet have an instance. Using a helper function in the
63986b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    //  namespace which will parse params and make calls into specific class instances
6399104ab082916e41467ef60baaab7a5a8b2e02c59cTobin Ehlis    return cvdescriptorset::ValidateUpdateDescriptorSets(dev_data->report_data, dev_data, descriptorWriteCount, pDescriptorWrites,
6400104ab082916e41467ef60baaab7a5a8b2e02c59cTobin Ehlis                                                         descriptorCopyCount, pDescriptorCopies);
64016b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis}
64026b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis// PostCallRecord* handles recording state updates following call down chain to UpdateDescriptorSets()
64036b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlisstatic void PostCallRecordUpdateDescriptorSets(layer_data *dev_data, uint32_t descriptorWriteCount,
64046b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                               const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
64056b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                               const VkCopyDescriptorSet *pDescriptorCopies) {
6406104ab082916e41467ef60baaab7a5a8b2e02c59cTobin Ehlis    cvdescriptorset::PerformUpdateDescriptorSets(dev_data, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
64076b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                                 pDescriptorCopies);
64086b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis}
64095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6410bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL UpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount,
6411bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
6412bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkCopyDescriptorSet *pDescriptorCopies) {
64136b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis    // Only map look-up at top level is for device-level layer_data
641456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
6415b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
64163251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = PreCallValidateUpdateDescriptorSets(dev_data, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
64173251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                    pDescriptorCopies);
6418b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
64193251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) {
64204a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.UpdateDescriptorSets(device, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
64214a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                      pDescriptorCopies);
64226b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis        lock.lock();
64236b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis        // Since UpdateDescriptorSets() is void, nothing to check prior to updating state
64246b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis        PostCallRecordUpdateDescriptorSets(dev_data, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
64256b67c2aac9862a21e0dd068966c8b0b3aaf0bafdTobin Ehlis                                           pDescriptorCopies);
64265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
64275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
64285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6429bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL AllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pCreateInfo,
6430bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                      VkCommandBuffer *pCommandBuffer) {
643156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
64324a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.AllocateCommandBuffers(device, pCreateInfo, pCommandBuffer);
64335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6434b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::unique_lock<std::mutex> lock(global_lock);
64359a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto pPool = GetCommandPoolNode(dev_data, pCreateInfo->commandPool);
6436cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes
6437cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes        if (pPool) {
643872d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis            for (uint32_t i = 0; i < pCreateInfo->commandBufferCount; i++) {
64395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // Add command buffer to its commandPool map
6440cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes                pPool->commandBuffers.push_back(pCommandBuffer[i]);
64415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                GLOBAL_CB_NODE *pCB = new GLOBAL_CB_NODE;
64425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                // Add command buffer to map
64435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                dev_data->commandBufferMap[pCommandBuffer[i]] = pCB;
64445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                resetCB(dev_data, pCommandBuffer[i]);
64455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pCB->createInfo = *pCreateInfo;
64465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pCB->device = device;
64475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
64485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6449b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
64505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
64515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
64525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
64535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6454883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis// Add bindings between the given cmd buffer & framebuffer and the framebuffer's children
6455c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlisstatic void AddFramebufferBinding(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, FRAMEBUFFER_STATE *fb_state) {
64569b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus    addCommandBufferBinding(&fb_state->cb_bindings, {HandleToUint64(fb_state->framebuffer), kVulkanObjectTypeFramebuffer},
64570245b74a083d2cb3b083571deb0fe13b4ab428a4Tobin Ehlis                            cb_state);
6458883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis    for (auto attachment : fb_state->attachments) {
6459883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        auto view_state = attachment.view_state;
6460883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        if (view_state) {
646103ea795b83fdf0099594808a1a57064dea7f02a1Tobin Ehlis            AddCommandBufferBindingImageView(dev_data, cb_state, view_state);
6462883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        }
64639a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto rp_state = GetRenderPassState(dev_data, fb_state->createInfo.renderPass);
6464883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        if (rp_state) {
64659b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus            addCommandBufferBinding(&rp_state->cb_bindings, {HandleToUint64(rp_state->renderPass), kVulkanObjectTypeRenderPass},
64669b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    cb_state);
6467883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        }
6468883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis    }
6469883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis}
6470883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis
6471bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL BeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo) {
64723251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
647356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6474b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
64755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Validate command buffer level
64769a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *cb_node = GetCBNode(dev_data, commandBuffer);
6477f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis    if (cb_node) {
64785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // This implicitly resets the Cmd Buffer so make sure any fence is done and then clear memory references
6479a7fef8833e0b4e1e4c7ea20ab56da451a6856c0cChris Forbes        if (cb_node->in_use.load()) {
64803251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6481315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_16e00062, "MEM",
648259ae0ccadec962d9ca2cce7584fad6c57c1a4458Tobin Ehlis                            "Calling vkBeginCommandBuffer() on active command buffer %p before it has completed. "
64833251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "You must check command buffer fence before this call. %s",
6484315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            commandBuffer, validation_error_map[VALIDATION_ERROR_16e00062]);
64855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6486f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        clear_cmd_buf_and_mem_references(dev_data, cb_node);
6487f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        if (cb_node->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
64885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // Secondary Command Buffer
64895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            const VkCommandBufferInheritanceInfo *pInfo = pBeginInfo->pInheritanceInfo;
64905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!pInfo) {
64913251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
64925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6493315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_16e00066, "DS",
6494bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "vkBeginCommandBuffer(): Secondary Command Buffer (0x%p) must have inheritance info. %s", commandBuffer,
6495315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_16e00066]);
64965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            } else {
64975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (pBeginInfo->flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT) {
64982c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                    assert(pInfo->renderPass);
64992c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                    string errorString = "";
65009a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    auto framebuffer = GetFramebufferState(dev_data, pInfo->framebuffer);
65012c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                    if (framebuffer) {
65022c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                        if ((framebuffer->createInfo.renderPass != pInfo->renderPass) &&
65032c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                            !verify_renderpass_compatibility(dev_data, framebuffer->renderPassCreateInfo.ptr(),
65049a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                                                             GetRenderPassState(dev_data, pInfo->renderPass)->createInfo.ptr(),
65052c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                                                             errorString)) {
65062c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                            // renderPass that framebuffer was created with must be compatible with local renderPass
65073251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
65089b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                            VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(commandBuffer), __LINE__,
6509315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                            VALIDATION_ERROR_0280006e, "DS",
65103251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            "vkBeginCommandBuffer(): Secondary Command "
65113251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            "Buffer (0x%p) renderPass (0x%" PRIxLEAST64
65123251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            ") is incompatible w/ framebuffer "
65133251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            "(0x%" PRIxLEAST64 ") w/ render pass (0x%" PRIxLEAST64 ") due to: %s. %s",
65149b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                            commandBuffer, HandleToUint64(pInfo->renderPass), HandleToUint64(pInfo->framebuffer),
65159b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                            HandleToUint64(framebuffer->createInfo.renderPass), errorString.c_str(),
6516315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                            validation_error_map[VALIDATION_ERROR_0280006e]);
65175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        }
65182c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                        // Connect this framebuffer and its children to this cmdBuffer
65192c09b45e970dcf95b0e03a2528662a93e0f5dc6fTobin Ehlis                        AddFramebufferBinding(dev_data, cb_node, framebuffer);
65205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
65215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
65224527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                if ((pInfo->occlusionQueryEnable == VK_FALSE || dev_data->enabled_features.occlusionQueryPrecise == VK_FALSE) &&
65235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    (pInfo->queryFlags & VK_QUERY_CONTROL_PRECISE_BIT)) {
65243251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
65259b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(commandBuffer), __LINE__,
6526315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    VALIDATION_ERROR_16e00068, "DS",
65273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "vkBeginCommandBuffer(): Secondary Command Buffer (0x%p) must not have "
65283251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "VK_QUERY_CONTROL_PRECISE_BIT if occulusionQuery is disabled or the device does not "
65293251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "support precise occlusion queries. %s",
6530315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    commandBuffer, validation_error_map[VALIDATION_ERROR_16e00068]);
65315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
65325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
65335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (pInfo && pInfo->renderPass != VK_NULL_HANDLE) {
65349a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto renderPass = GetRenderPassState(dev_data, pInfo->renderPass);
653516387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                if (renderPass) {
6536fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes                    if (pInfo->subpass >= renderPass->createInfo.subpassCount) {
65373251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
65389b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                        VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(commandBuffer), __LINE__,
6539315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                        VALIDATION_ERROR_0280006c, "DS",
65403251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                        "vkBeginCommandBuffer(): Secondary Command Buffers (0x%p) must have a subpass index (%d) "
65413251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                        "that is less than the number of subpasses (%d). %s",
65423251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                        commandBuffer, pInfo->subpass, renderPass->createInfo.subpassCount,
6543315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                        validation_error_map[VALIDATION_ERROR_0280006c]);
65445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
65455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
65465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
65475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6548f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        if (CB_RECORDING == cb_node->state) {
65493251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6550315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_16e00062, "DS",
65513251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkBeginCommandBuffer(): Cannot call Begin on command buffer (0x%p"
65523251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            ") in the RECORDING state. Must first call vkEndCommandBuffer(). %s",
6553315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            commandBuffer, validation_error_map[VALIDATION_ERROR_16e00062]);
6554347d4d3139a1e743ed85bd375c20fd35bbe68d74Chris Forbes        } else if (CB_RECORDED == cb_node->state || (CB_INVALID == cb_node->state && CMD_END == cb_node->last_cmd)) {
6555f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            VkCommandPool cmdPool = cb_node->createInfo.commandPool;
65569a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pPool = GetCommandPoolNode(dev_data, cmdPool);
6557cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes            if (!(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT & pPool->createFlags)) {
65583251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
65595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6560315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_16e00064, "DS",
6561226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                            "Call to vkBeginCommandBuffer() on command buffer (0x%p"
6562414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                            ") attempts to implicitly reset cmdBuffer created from command pool (0x%" PRIxLEAST64
65634527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton                            ") that does NOT have the VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT bit set. %s",
6564315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            commandBuffer, HandleToUint64(cmdPool), validation_error_map[VALIDATION_ERROR_16e00064]);
65655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
65665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            resetCB(dev_data, commandBuffer);
65675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
65685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Set updated state here in case implicit reset occurs above
6569f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        cb_node->state = CB_RECORDING;
6570f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        cb_node->beginInfo = *pBeginInfo;
6571f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis        if (cb_node->beginInfo.pInheritanceInfo) {
6572f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->inheritanceInfo = *(cb_node->beginInfo.pInheritanceInfo);
6573f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->beginInfo.pInheritanceInfo = &cb_node->inheritanceInfo;
6574888e1d268098177fde4a2263e3d7b7cc415f1debMark Young            // If we are a secondary command-buffer and inheriting.  Update the items we should inherit.
6575f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            if ((cb_node->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) &&
6576f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                (cb_node->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
65779a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                cb_node->activeRenderPass = GetRenderPassState(dev_data, cb_node->beginInfo.pInheritanceInfo->renderPass);
6578f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                cb_node->activeSubpass = cb_node->beginInfo.pInheritanceInfo->subpass;
6579350841afb70bf8dcfc3c6ec6b66f0aaa639553a3Tobin Ehlis                cb_node->activeFramebuffer = cb_node->beginInfo.pInheritanceInfo->framebuffer;
6580f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                cb_node->framebuffers.insert(cb_node->beginInfo.pInheritanceInfo->framebuffer);
6581888e1d268098177fde4a2263e3d7b7cc415f1debMark Young            }
65825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
65835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6584b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
65853251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) {
65865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        return VK_ERROR_VALIDATION_FAILED_EXT;
65875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
65884a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.BeginCommandBuffer(commandBuffer, pBeginInfo);
6589400cff9fad0e19c80f6c9ed1181795d411a4bec5Tobin Ehlis
65905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
65915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
65925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
659389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL EndCommandBuffer(VkCommandBuffer commandBuffer) {
65943251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
659556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6596b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
65979a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
65985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
65994527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton        if ((VK_COMMAND_BUFFER_LEVEL_PRIMARY == pCB->createInfo.level) ||
66004527dcafa951a1fa931b258bbcd2d48b283610a7Dave Houlton            !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
6601fd61966f8d41b5bce15620b70563b7864cbb28feCody Northrop            // This needs spec clarification to update valid usage, see comments in PR:
6602fd61966f8d41b5bce15620b70563b7864cbb28feCody Northrop            // https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/pull/516#discussion_r63013756
6603315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            skip |= insideRenderPass(dev_data, pCB, "vkEndCommandBuffer()", VALIDATION_ERROR_27400078);
6604fd61966f8d41b5bce15620b70563b7864cbb28feCody Northrop        }
66053251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_END, "vkEndCommandBuffer()");
66061ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_END);
66075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto query : pCB->activeQueries) {
66083251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6609315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_2740007a, "DS",
66103251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Ending command buffer with in progress query: queryPool 0x%" PRIx64 ", index %d. %s",
6611315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(query.pool), query.index, validation_error_map[VALIDATION_ERROR_2740007a]);
66125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
66135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
66143251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) {
6615b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
66160d9453d85335963d6cabfbf400b058dc905ea238Chris Forbes        auto result = dev_data->dispatch_table.EndCommandBuffer(commandBuffer);
6617b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
66185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (VK_SUCCESS == result) {
66195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pCB->state = CB_RECORDED;
66205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
66210d9453d85335963d6cabfbf400b058dc905ea238Chris Forbes        return result;
66225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
66230d9453d85335963d6cabfbf400b058dc905ea238Chris Forbes        return VK_ERROR_VALIDATION_FAILED_EXT;
66245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
66255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
66265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6627bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL ResetCommandBuffer(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags) {
66283251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
662956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6630b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
66319a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
66325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkCommandPool cmdPool = pCB->createInfo.commandPool;
66339a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pPool = GetCommandPoolNode(dev_data, cmdPool);
6634cd9a648074f67a1d44c15a056b90fc66da8ead17Chris Forbes    if (!(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT & pPool->createFlags)) {
66353251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6636315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_3260005c, "DS",
66373251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Attempt to reset command buffer (0x%p) created from command pool (0x%" PRIxLEAST64
66383251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        ") that does NOT have the VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT bit set. %s",
6639315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        commandBuffer, HandleToUint64(cmdPool), validation_error_map[VALIDATION_ERROR_3260005c]);
66405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6641315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= checkCommandBufferInFlight(dev_data, pCB, "reset", VALIDATION_ERROR_3260005a);
6642b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
66433251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
66444a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.ResetCommandBuffer(commandBuffer, flags);
66455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
6646b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.lock();
66475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        resetCB(dev_data, commandBuffer);
6648b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        lock.unlock();
66495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
66505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
66515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
665293c396d566d722dc5c6f438eae212da0e9337ba3Mark Lobodzinski
6653bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBindPipeline(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
6654bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           VkPipeline pipeline) {
6655e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis    bool skip = false;
665656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6657b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
66589a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
6659e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis    if (cb_state) {
6660baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdBindPipeline()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
6661315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                      VALIDATION_ERROR_18002415);
666229f880e9c3c837307e7a19c0ef7275448d483e04Tobin Ehlis        skip |= ValidateCmd(dev_data, cb_state, CMD_BINDPIPELINE, "vkCmdBindPipeline()");
66631ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(cb_state, CMD_BINDPIPELINE);
6664e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        if ((VK_PIPELINE_BIND_POINT_COMPUTE == pipelineBindPoint) && (cb_state->activeRenderPass)) {
6665e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            skip |=
66665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
66679b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(pipeline), __LINE__, DRAWSTATE_INVALID_RENDERPASS_CMD, "DS",
6668414e9a4117b500eac650d8b8f01a6e1b22d05aaeMark Mueller                        "Incorrectly binding compute pipeline (0x%" PRIxLEAST64 ") during active RenderPass (0x%" PRIxLEAST64 ")",
66699b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(pipeline), HandleToUint64(cb_state->activeRenderPass->renderPass));
66705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
6671315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        // TODO: VALIDATION_ERROR_18000612 VALIDATION_ERROR_18000616
66725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6673e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        PIPELINE_STATE *pipe_state = getPipelineState(dev_data, pipeline);
6674e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        if (pipe_state) {
6675e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            cb_state->lastBound[pipelineBindPoint].pipeline_state = pipe_state;
6676e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            set_cb_pso_status(cb_state, pipe_state);
6677e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            set_pipeline_state(pipe_state);
6678daaf8f4ce66b35b4509bb7a7fdf4256e4f324ba7Mark Lobodzinski            skip |= validate_dual_src_blend_feature(dev_data, pipe_state);
66795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
6680e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
6681315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(pipeline), __LINE__, VALIDATION_ERROR_18027e01, "DS",
66829b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "Attempt to bind Pipeline 0x%" PRIxLEAST64 " that doesn't exist! %s", HandleToUint64(pipeline),
6683315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_18027e01]);
6684e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        }
66859b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus        addCommandBufferBinding(&pipe_state->cb_bindings, {HandleToUint64(pipeline), kVulkanObjectTypePipeline}, cb_state);
6686e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis        if (VK_PIPELINE_BIND_POINT_GRAPHICS == pipelineBindPoint) {
6687e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            // Add binding for child renderpass
66889a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto rp_state = GetRenderPassState(dev_data, pipe_state->graphicsPipelineCI.renderPass);
6689e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            if (rp_state) {
66909b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                addCommandBufferBinding(&rp_state->cb_bindings, {HandleToUint64(rp_state->renderPass), kVulkanObjectTypeRenderPass},
66919b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                        cb_state);
6692e92495715edaa63453ce5775bf60f3795df72876Tobin Ehlis            }
66935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
66945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6695b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
6696cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdBindPipeline(commandBuffer, pipelineBindPoint, pipeline);
66975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
66985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6699bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetViewport(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount,
6700bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                          const VkViewport *pViewports) {
67013251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
670256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6703b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
67049a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
67055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
6706315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetViewport()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1e002415);
67073251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETVIEWPORTSTATE, "vkCmdSetViewport()");
67081ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETVIEWPORTSTATE);
6709bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pCB->viewportMask |= ((1u << viewportCount) - 1u) << firstViewport;
67105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6711b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
67123251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetViewport(commandBuffer, firstViewport, viewportCount, pViewports);
67135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
67145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6715bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetScissor(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount,
6716bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         const VkRect2D *pScissors) {
67173251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
671856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6719b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
67209a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
67215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
6722315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetScissor()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1d802415);
67233251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETSCISSORSTATE, "vkCmdSetScissor()");
67241ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETSCISSORSTATE);
6725bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pCB->scissorMask |= ((1u << scissorCount) - 1u) << firstScissor;
67265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6727b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
67283251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetScissor(commandBuffer, firstScissor, scissorCount, pScissors);
67295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
67305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
673189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth) {
67323251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
673356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6734b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
67359a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
67365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
6737315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetLineWidth()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1d602415);
67383251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETLINEWIDTHSTATE, "vkCmdSetLineWidth()");
67391ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETLINEWIDTHSTATE);
67405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_LINE_WIDTH_SET;
6741a27508babf63d50aea75883a3702979193c23683Mark Young
67424c0df90de562aa248b524a28b355765d8e3eff25Tobin Ehlis        PIPELINE_STATE *pPipeTrav = pCB->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].pipeline_state;
6743a27508babf63d50aea75883a3702979193c23683Mark Young        if (pPipeTrav != NULL && !isDynamic(pPipeTrav, VK_DYNAMIC_STATE_LINE_WIDTH)) {
67443251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6745315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_1d600626, "DS",
67463251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkCmdSetLineWidth called but pipeline was created without VK_DYNAMIC_STATE_LINE_WIDTH "
67473251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "flag.  This is undefined behavior and could be ignored. %s",
6748315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_1d600626]);
6749a27508babf63d50aea75883a3702979193c23683Mark Young        } else {
67509b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus            skip |= verifyLineWidth(dev_data, DRAWSTATE_INVALID_SET, kVulkanObjectTypeCommandBuffer, HandleToUint64(commandBuffer),
67519b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    lineWidth);
6752a27508babf63d50aea75883a3702979193c23683Mark Young        }
67535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6754b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
67553251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetLineWidth(commandBuffer, lineWidth);
67565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
67575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6758bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetDepthBias(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp,
6759bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           float depthBiasSlopeFactor) {
67603251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
676156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6762b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
67639a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
67645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
6765315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetDepthBias()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1cc02415);
67663251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETDEPTHBIASSTATE, "vkCmdSetDepthBias()");
6767434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski        if ((depthBiasClamp != 0.0) && (!dev_data->enabled_features.depthBiasClamp)) {
67683251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6769315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_1cc0062c, "DS",
67703251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkCmdSetDepthBias(): the depthBiasClamp device feature is disabled: the depthBiasClamp "
67713251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "parameter must be set to 0.0. %s",
6772315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_1cc0062c]);
6773434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski        }
67743251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        if (!skip) {
6775434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski            UpdateCmdBufferLastCmd(pCB, CMD_SETDEPTHBIASSTATE);
6776434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski            pCB->status |= CBSTATUS_DEPTH_BIAS_SET;
6777434c3e2a778a3ca5a0a5414cbedd7c0f20a883b7Mark Lobodzinski        }
67785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6779b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
67803251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip)
67814a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdSetDepthBias(commandBuffer, depthBiasConstantFactor, depthBiasClamp, depthBiasSlopeFactor);
67825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
67835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
678489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdSetBlendConstants(VkCommandBuffer commandBuffer, const float blendConstants[4]) {
67853251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
678656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6787b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
67889a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
67895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
6790315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetBlendConstants()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1ca02415);
67913251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETBLENDSTATE, "vkCmdSetBlendConstants()");
67921ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETBLENDSTATE);
67933d3e06b40a06f099e741b9299efa66bddb69a074Tobin Ehlis        pCB->status |= CBSTATUS_BLEND_CONSTANTS_SET;
67945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6795b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
67963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetBlendConstants(commandBuffer, blendConstants);
67975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
67985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6799bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetDepthBounds(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds) {
68003251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
680156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6802b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
68039a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
68045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
6805315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetDepthBounds()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1ce02415);
68063251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETDEPTHBOUNDSSTATE, "vkCmdSetDepthBounds()");
68071ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETDEPTHBOUNDSSTATE);
68085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_DEPTH_BOUNDS_SET;
68095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6810b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
68113251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetDepthBounds(commandBuffer, minDepthBounds, maxDepthBounds);
68125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
68135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6814bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetStencilCompareMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask,
6815bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                    uint32_t compareMask) {
68163251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
681756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6818b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
68199a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
68205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
6821315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |=
6822315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetStencilCompareMask()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1da02415);
68233251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETSTENCILREADMASKSTATE, "vkCmdSetStencilCompareMask()");
68241ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETSTENCILREADMASKSTATE);
68255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_STENCIL_READ_MASK_SET;
68265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6827b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
68283251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetStencilCompareMask(commandBuffer, faceMask, compareMask);
68295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
68305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6831bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetStencilWriteMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask) {
68323251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
683356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6834b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
68359a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
68365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
6837315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |=
6838315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetStencilWriteMask()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1de02415);
68393251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETSTENCILWRITEMASKSTATE, "vkCmdSetStencilWriteMask()");
68401ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETSTENCILWRITEMASKSTATE);
68415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_STENCIL_WRITE_MASK_SET;
68425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6843b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
68443251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetStencilWriteMask(commandBuffer, faceMask, writeMask);
68455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
68465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6847bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetStencilReference(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference) {
68483251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
684956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6850b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
68519a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
68525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
6853315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |=
6854315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetStencilReference()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1dc02415);
68553251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETSTENCILREFERENCESTATE, "vkCmdSetStencilReference()");
68561ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETSTENCILREFERENCESTATE);
68575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->status |= CBSTATUS_STENCIL_REFERENCE_SET;
68585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
6859b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
68603251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetStencilReference(commandBuffer, faceMask, reference);
68615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
68625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
6863bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBindDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
6864bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 VkPipelineLayout layout, uint32_t firstSet, uint32_t setCount,
6865bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkDescriptorSet *pDescriptorSets, uint32_t dynamicOffsetCount,
6866bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const uint32_t *pDynamicOffsets) {
6867946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
686856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
6869b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
6870946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
6871946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (cb_state) {
6872baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdBindDescriptorSets()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
6873315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                      VALIDATION_ERROR_17c02415);
6874946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_state, CMD_BINDDESCRIPTORSETS, "vkCmdBindDescriptorSets()");
6875ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        // Track total count of dynamic descriptor types to make sure we have an offset for each one
6876946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        uint32_t total_dynamic_descriptors = 0;
6877946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        string error_string = "";
6878946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        uint32_t last_set_index = firstSet + setCount - 1;
6879946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        if (last_set_index >= cb_state->lastBound[pipelineBindPoint].boundDescriptorSets.size()) {
6880946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            cb_state->lastBound[pipelineBindPoint].boundDescriptorSets.resize(last_set_index + 1);
6881946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            cb_state->lastBound[pipelineBindPoint].dynamicOffsets.resize(last_set_index + 1);
6882946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        }
6883946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        auto old_final_bound_set = cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[last_set_index];
6884ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        auto pipeline_layout = getPipelineLayout(dev_data, layout);
6885ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        for (uint32_t set_idx = 0; set_idx < setCount; set_idx++) {
6886ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            cvdescriptorset::DescriptorSet *descriptor_set = GetSetNode(dev_data, pDescriptorSets[set_idx]);
6887ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            if (descriptor_set) {
6888946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                cb_state->lastBound[pipelineBindPoint].pipeline_layout = *pipeline_layout;
6889946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[set_idx + firstSet] = descriptor_set;
6890946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT,
68919b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, HandleToUint64(pDescriptorSets[set_idx]), __LINE__,
6892946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                DRAWSTATE_NONE, "DS", "Descriptor Set 0x%" PRIxLEAST64 " bound on pipeline %s",
68939b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pDescriptorSets[set_idx]), string_VkPipelineBindPoint(pipelineBindPoint));
6894ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                if (!descriptor_set->IsUpdated() && (descriptor_set->GetTotalDescriptorCount() != 0)) {
6895946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
68969b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, HandleToUint64(pDescriptorSets[set_idx]),
68979b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS",
6898946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    "Descriptor Set 0x%" PRIxLEAST64
6899946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    " bound but it was never updated. You may want to either update it or not bind it.",
69009b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    HandleToUint64(pDescriptorSets[set_idx]));
6901ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                }
6902ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                // Verify that set being bound is compatible with overlapping setLayout of pipelineLayout
690312b7fc342b53fbdd399aae4a85959e37685936acChris Forbes                if (!verify_set_layout_compatibility(descriptor_set, pipeline_layout, set_idx + firstSet, error_string)) {
6904946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
69059b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, HandleToUint64(pDescriptorSets[set_idx]),
6906315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    __LINE__, VALIDATION_ERROR_17c002cc, "DS",
6907946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    "descriptorSet #%u being bound is not compatible with overlapping descriptorSetLayout "
6908946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    "at index %u of pipelineLayout 0x%" PRIxLEAST64 " due to: %s. %s",
69099b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    set_idx, set_idx + firstSet, HandleToUint64(layout), error_string.c_str(),
6910315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    validation_error_map[VALIDATION_ERROR_17c002cc]);
69115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
6912ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski
6913946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                auto set_dynamic_descriptor_count = descriptor_set->GetDynamicDescriptorCount();
6914ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski
6915946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                cb_state->lastBound[pipelineBindPoint].dynamicOffsets[firstSet + set_idx].clear();
6916ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski
6917946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                if (set_dynamic_descriptor_count) {
6918ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                    // First make sure we won't overstep bounds of pDynamicOffsets array
6919946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    if ((total_dynamic_descriptors + set_dynamic_descriptor_count) > dynamicOffsetCount) {
69209b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        skip |= log_msg(
69219b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
69229b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pDescriptorSets[set_idx]), __LINE__, DRAWSTATE_INVALID_DYNAMIC_OFFSET_COUNT, "DS",
69239b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "descriptorSet #%u (0x%" PRIxLEAST64
69249b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            ") requires %u dynamicOffsets, but only %u dynamicOffsets are left in pDynamicOffsets "
69259b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "array. There must be one dynamic offset for each dynamic descriptor being bound.",
69269b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            set_idx, HandleToUint64(pDescriptorSets[set_idx]), descriptor_set->GetDynamicDescriptorCount(),
69279b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            (dynamicOffsetCount - total_dynamic_descriptors));
6928ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                    } else {  // Validate and store dynamic offsets with the set
6929ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                        // Validate Dynamic Offset Minimums
6930946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        uint32_t cur_dyn_offset = total_dynamic_descriptors;
6931ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                        for (uint32_t d = 0; d < descriptor_set->GetTotalDescriptorCount(); d++) {
6932ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            if (descriptor_set->GetTypeFromGlobalIndex(d) == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) {
693316769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton                                if (SafeModulo(
6934ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        pDynamicOffsets[cur_dyn_offset],
6935ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment) != 0) {
6936315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    skip |=
6937315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
6938315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__,
6939315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                VALIDATION_ERROR_17c002d4, "DS",
6940315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                "vkCmdBindDescriptorSets(): pDynamicOffsets[%d] is %d but must be a multiple of "
6941315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                "device limit minUniformBufferOffsetAlignment 0x%" PRIxLEAST64 ". %s",
6942315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                cur_dyn_offset, pDynamicOffsets[cur_dyn_offset],
6943315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment,
6944315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                validation_error_map[VALIDATION_ERROR_17c002d4]);
6945ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                }
6946ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                cur_dyn_offset++;
6947ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            } else if (descriptor_set->GetTypeFromGlobalIndex(d) == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
694816769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton                                if (SafeModulo(
6949ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        pDynamicOffsets[cur_dyn_offset],
6950ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                        dev_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment) != 0) {
6951315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    skip |=
6952315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
6953315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__,
6954315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                VALIDATION_ERROR_17c002d4, "DS",
6955315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                "vkCmdBindDescriptorSets(): pDynamicOffsets[%d] is %d but must be a multiple of "
6956315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                "device limit minStorageBufferOffsetAlignment 0x%" PRIxLEAST64 ". %s",
6957315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                cur_dyn_offset, pDynamicOffsets[cur_dyn_offset],
6958315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                dev_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment,
6959315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                validation_error_map[VALIDATION_ERROR_17c002d4]);
6960ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                }
6961ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                                cur_dyn_offset++;
6962ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            }
696372d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                        }
6964ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski
6965946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        cb_state->lastBound[pipelineBindPoint].dynamicOffsets[firstSet + set_idx] =
6966946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            std::vector<uint32_t>(pDynamicOffsets + total_dynamic_descriptors,
6967946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                                  pDynamicOffsets + total_dynamic_descriptors + set_dynamic_descriptor_count);
6968ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                        // Keep running total of dynamic descriptor count to verify at the end
6969946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        total_dynamic_descriptors += set_dynamic_descriptor_count;
697072d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                    }
697172d66f0c1639cbaca92459498452d06db32d7aefTobin Ehlis                }
6972ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            } else {
69739b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                skip |=
69749b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
69759b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pDescriptorSets[set_idx]), __LINE__, DRAWSTATE_INVALID_SET, "DS",
69769b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "Attempt to bind descriptor set 0x%" PRIxLEAST64 " that doesn't exist!",
69779b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pDescriptorSets[set_idx]));
6978ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            }
6979946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            UpdateCmdBufferLastCmd(cb_state, CMD_BINDDESCRIPTORSETS);
6980ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            // For any previously bound sets, need to set them to "invalid" if they were disturbed by this update
6981ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            if (firstSet > 0) {  // Check set #s below the first bound set
6982ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                for (uint32_t i = 0; i < firstSet; ++i) {
6983946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    if (cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[i] &&
698412b7fc342b53fbdd399aae4a85959e37685936acChris Forbes                        !verify_set_layout_compatibility(cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[i],
6985946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                                         pipeline_layout, i, error_string)) {
6986946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        skip |= log_msg(
6987ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
6988ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                            VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
69899b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[i]), __LINE__, DRAWSTATE_NONE,
69909b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "DS", "DescriptorSet 0x%" PRIxLEAST64
69919b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                  " previously bound as set #%u was disturbed by newly bound pipelineLayout (0x%" PRIxLEAST64 ")",
69929b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[i]), i,
69939b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(layout));
6994946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                        cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[i] = VK_NULL_HANDLE;
69955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
69965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
69975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
6998ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            // Check if newly last bound set invalidates any remaining bound sets
6999946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            if ((cb_state->lastBound[pipelineBindPoint].boundDescriptorSets.size() - 1) > (last_set_index)) {
7000946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                if (old_final_bound_set &&
700112b7fc342b53fbdd399aae4a85959e37685936acChris Forbes                    !verify_set_layout_compatibility(old_final_bound_set, pipeline_layout, last_set_index, error_string)) {
7002946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    auto old_set = old_final_bound_set->GetSet();
7003946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
70049b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, HandleToUint64(old_set), __LINE__,
7005946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                    DRAWSTATE_NONE, "DS", "DescriptorSet 0x%" PRIxLEAST64
7006946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                                          " previously bound as set #%u is incompatible with set 0x%" PRIxLEAST64
7007946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                                          " newly bound as set #%u so set #%u and any subsequent sets were "
7008946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                                          "disturbed by newly bound pipelineLayout (0x%" PRIxLEAST64 ")",
70099b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    HandleToUint64(old_set), last_set_index,
70109b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    HandleToUint64(cb_state->lastBound[pipelineBindPoint].boundDescriptorSets[last_set_index]),
70119b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    last_set_index, last_set_index + 1, HandleToUint64(layout));
7012946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                    cb_state->lastBound[pipelineBindPoint].boundDescriptorSets.resize(last_set_index + 1);
7013ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                }
7014787f29d93dee194c015789cf61c079504c980572Tobin Ehlis            }
7015ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        }
7016ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        //  dynamicOffsetCount must equal the total number of dynamic descriptors in the sets being bound
7017946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        if (total_dynamic_descriptors != dynamicOffsetCount) {
7018315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            skip |=
7019315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
7020315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_17c002ce, "DS",
7021315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        "Attempting to bind %u descriptorSets with %u dynamic descriptors, but dynamicOffsetCount "
7022315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        "is %u. It should exactly match the number of dynamic descriptors. %s",
7023315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        setCount, total_dynamic_descriptors, dynamicOffsetCount, validation_error_map[VALIDATION_ERROR_17c002ce]);
70245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
70255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7026b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7027946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip)
70284a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdBindDescriptorSets(commandBuffer, pipelineBindPoint, layout, firstSet, setCount,
70294a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                       pDescriptorSets, dynamicOffsetCount, pDynamicOffsets);
70305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
70315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7032bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBindIndexBuffer(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
7033bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              VkIndexType indexType) {
7034946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
703556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7036593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis    // TODO : Somewhere need to verify that IBs have correct usage state flagged
7037b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7038b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski
70399a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto buffer_state = GetBufferState(dev_data, buffer);
70409a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
70415cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (cb_node && buffer_state) {
7042315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |=
7043315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            ValidateCmdQueueFlags(dev_data, cb_node, "vkCmdBindIndexBuffer()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_17e02415);
7044946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_node, CMD_BINDINDEXBUFFER, "vkCmdBindIndexBuffer()");
7045315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateMemoryIsBoundToBuffer(dev_data, buffer_state, "vkCmdBindIndexBuffer()", VALIDATION_ERROR_17e00364);
7046ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        std::function<bool()> function = [=]() {
7047ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            return ValidateBufferMemoryIsValid(dev_data, buffer_state, "vkCmdBindIndexBuffer()");
7048ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        };
7049ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        cb_node->validate_functions.push_back(function);
7050ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        UpdateCmdBufferLastCmd(cb_node, CMD_BINDINDEXBUFFER);
7051ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        VkDeviceSize offset_align = 0;
7052ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        switch (indexType) {
7053ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            case VK_INDEX_TYPE_UINT16:
7054ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                offset_align = 2;
7055ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                break;
7056ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            case VK_INDEX_TYPE_UINT32:
7057ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                offset_align = 4;
7058ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                break;
7059ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            default:
7060ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                // ParamChecker should catch bad enum, we'll also throw alignment error below if offset_align stays 0
7061ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                break;
70625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7063ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        if (!offset_align || (offset % offset_align)) {
7064df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
70659b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(commandBuffer), __LINE__, DRAWSTATE_VTX_INDEX_ALIGNMENT_ERROR, "DS",
7066946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            "vkCmdBindIndexBuffer() offset (0x%" PRIxLEAST64 ") does not fall on alignment (%s) boundary.", offset,
7067946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                            string_VkIndexType(indexType));
7068ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        }
7069ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        cb_node->status |= CBSTATUS_INDEX_BUFFER_BOUND;
7070ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
7071ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
70725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7073b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7074946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdBindIndexBuffer(commandBuffer, buffer, offset, indexType);
70755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
70765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
70775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisvoid updateResourceTracking(GLOBAL_CB_NODE *pCB, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer *pBuffers) {
70785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t end = firstBinding + bindingCount;
70795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB->currentDrawData.buffers.size() < end) {
70805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->currentDrawData.buffers.resize(end);
70815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
70825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < bindingCount; ++i) {
70835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->currentDrawData.buffers[i + firstBinding] = pBuffers[i];
70845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
70855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
70865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7087e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic inline void updateResourceTrackingOnDraw(GLOBAL_CB_NODE *pCB) { pCB->drawData.push_back(pCB->currentDrawData); }
70885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7089bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBindVertexBuffers(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount,
7090bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkBuffer *pBuffers, const VkDeviceSize *pOffsets) {
7091946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
709256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7093593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis    // TODO : Somewhere need to verify that VBs have correct usage state flagged
7094b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7095b3c2024e0ed61d7f68630d7eb7c8c03100689bb1Mark Lobodzinski
70969a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
70979f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis    if (cb_node) {
7098315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |=
7099315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            ValidateCmdQueueFlags(dev_data, cb_node, "vkCmdBindVertexBuffers()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_18202415);
7100baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmd(dev_data, cb_node, CMD_BINDVERTEXBUFFER, "vkCmdBindVertexBuffers()");
7101ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        for (uint32_t i = 0; i < bindingCount; ++i) {
7102ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            auto buffer_state = GetBufferState(dev_data, pBuffers[i]);
7103ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            assert(buffer_state);
7104315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            skip |= ValidateMemoryIsBoundToBuffer(dev_data, buffer_state, "vkCmdBindVertexBuffers()", VALIDATION_ERROR_182004e8);
7105ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            std::function<bool()> function = [=]() {
7106ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski                return ValidateBufferMemoryIsValid(dev_data, buffer_state, "vkCmdBindVertexBuffers()");
7107ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            };
7108ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski            cb_node->validate_functions.push_back(function);
71095fe7f75f980a78c0179ff93438d8786e6cb44b20Tony Barbour            if (pOffsets[i] >= buffer_state->createInfo.size) {
71105fe7f75f980a78c0179ff93438d8786e6cb44b20Tony Barbour                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
7111315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                HandleToUint64(buffer_state->buffer), __LINE__, VALIDATION_ERROR_182004e4, "DS",
71125fe7f75f980a78c0179ff93438d8786e6cb44b20Tony Barbour                                "vkCmdBindVertexBuffers() offset (0x%" PRIxLEAST64 ") is beyond the end of the buffer. %s",
7113315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                pOffsets[i], validation_error_map[VALIDATION_ERROR_182004e4]);
71145fe7f75f980a78c0179ff93438d8786e6cb44b20Tony Barbour            }
71155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7116ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        UpdateCmdBufferLastCmd(cb_node, CMD_BINDVERTEXBUFFER);
7117ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        updateResourceTracking(cb_node, firstBinding, bindingCount, pBuffers);
71185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
71197828015969ab31ee01d597f0288cbb124b637fcdMark Lobodzinski        assert(0);
71205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7121b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7122946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdBindVertexBuffers(commandBuffer, firstBinding, bindingCount, pBuffers, pOffsets);
71235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
71245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
712525002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski// Expects global_lock to be held by caller
71265569d6457ac22e7d245f3cdee045e71ffbc8b06eTobin Ehlisstatic void MarkStoreImagesAndBuffersAsWritten(layer_data *dev_data, GLOBAL_CB_NODE *pCB) {
71277a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis    for (auto imageView : pCB->updateImages) {
71289a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto view_state = GetImageViewState(dev_data, imageView);
7129cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!view_state) continue;
7130249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis
71319a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto image_state = GetImageState(dev_data, view_state->create_info.image);
71321facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        assert(image_state);
7133e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
71341facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            SetImageMemoryValid(dev_data, image_state, true);
7135e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
71367a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        };
71377a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        pCB->validate_functions.push_back(function);
71387a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis    }
71397a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis    for (auto buffer : pCB->updateBuffers) {
71409a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto buffer_state = GetBufferState(dev_data, buffer);
71415cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        assert(buffer_state);
7142e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
71435cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            SetBufferMemoryValid(dev_data, buffer_state, true);
7144e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
71457a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        };
71467a3985a8a9d255dcca9f5992ca2262c7e5df41c6Tobin Ehlis        pCB->validate_functions.push_back(function);
71475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
71485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
71495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7150ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis// Generic function to handle validation for all CmdDraw* type functions
7151ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool ValidateCmdDrawType(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed, VkPipelineBindPoint bind_point,
7152baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                CMD_TYPE cmd_type, GLOBAL_CB_NODE **cb_state, const char *caller, VkQueueFlags queue_flags,
7153baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                UNIQUE_VALIDATION_ERROR_CODE queue_flag_code, UNIQUE_VALIDATION_ERROR_CODE msg_code,
7154baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt                                UNIQUE_VALIDATION_ERROR_CODE const dynamic_state_msg_code) {
715558b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    bool skip = false;
71569a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *cb_state = GetCBNode(dev_data, cmd_buffer);
715758b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    if (*cb_state) {
7158baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, *cb_state, caller, queue_flags, queue_flag_code);
7159ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis        skip |= ValidateCmd(dev_data, *cb_state, cmd_type, caller);
71604f5a71335df5361d740a23b4548d54fc72a28d4fJeremy Hayes        skip |= ValidateDrawState(dev_data, *cb_state, indexed, bind_point, caller, dynamic_state_msg_code);
716125d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis        skip |= (VK_PIPELINE_BIND_POINT_GRAPHICS == bind_point) ? outsideRenderPass(dev_data, *cb_state, caller, msg_code)
716225d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis                                                                : insideRenderPass(dev_data, *cb_state, caller, msg_code);
716358b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    }
716458b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    return skip;
716558b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis}
716658b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis
716725d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis// Generic function to handle state update for all CmdDraw* and CmdDispatch* type functions
7168ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void UpdateStateCmdDrawDispatchType(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
7169ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                           CMD_TYPE cmd_type) {
7170ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateDrawState(dev_data, cb_state, bind_point);
71712f921d33544c162dcb726fc3c7b915e89c02ff24Tobin Ehlis    MarkStoreImagesAndBuffersAsWritten(dev_data, cb_state);
71721ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis    UpdateCmdBufferLastCmd(cb_state, cmd_type);
717325d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis}
717425d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis
7175ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis// Generic function to handle state update for all CmdDraw* type functions
7176ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void UpdateStateCmdDrawType(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
7177b68b13ed4952bce61f6ebb0023542660c26b0562Chris Forbes                                   CMD_TYPE cmd_type) {
7178ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawDispatchType(dev_data, cb_state, bind_point, cmd_type);
7179c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis    updateResourceTrackingOnDraw(cb_state);
7180b68b13ed4952bce61f6ebb0023542660c26b0562Chris Forbes    cb_state->hasDrawCmd = true;
7181ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis}
7182ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis
7183ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDraw(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed, VkPipelineBindPoint bind_point,
7184ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                   GLOBAL_CB_NODE **cb_state, const char *caller) {
7185baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    return ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAW, cb_state, caller, VK_QUEUE_GRAPHICS_BIT,
7186315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                               VALIDATION_ERROR_1a202415, VALIDATION_ERROR_1a200017, VALIDATION_ERROR_1a200376);
7187ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis}
7188ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis
7189ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDraw(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point) {
7190b68b13ed4952bce61f6ebb0023542660c26b0562Chris Forbes    UpdateStateCmdDrawType(dev_data, cb_state, bind_point, CMD_DRAW);
7191c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis}
7192c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis
719389d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount,
719489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                   uint32_t firstVertex, uint32_t firstInstance) {
719556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
719658b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
7197b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7198ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    bool skip = PreCallValidateCmdDraw(dev_data, commandBuffer, false, VK_PIPELINE_BIND_POINT_GRAPHICS, &cb_state, "vkCmdDraw()");
7199b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
720058b923895f7f6be1b7d48bd4ee3e85e0b3dd0c4dTobin Ehlis    if (!skip) {
72014a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDraw(commandBuffer, vertexCount, instanceCount, firstVertex, firstInstance);
7202c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis        lock.lock();
7203ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDraw(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS);
7204c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis        lock.unlock();
7205c0b225e42808ba8fada7a2f67ecd662e376ccf15Tobin Ehlis    }
72065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
72075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7208ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDrawIndexed(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed,
7209ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                          VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state, const char *caller) {
7210baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    return ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAWINDEXED, cb_state, caller, VK_QUEUE_GRAPHICS_BIT,
7211315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                               VALIDATION_ERROR_1a402415, VALIDATION_ERROR_1a400017, VALIDATION_ERROR_1a40039c);
7212ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis}
7213ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis
7214ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDrawIndexed(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point) {
7215b68b13ed4952bce61f6ebb0023542660c26b0562Chris Forbes    UpdateStateCmdDrawType(dev_data, cb_state, bind_point, CMD_DRAWINDEXED);
7216ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis}
7217ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis
7218bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount,
7219bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                          uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance) {
722056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7221ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
7222b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7223ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    bool skip = PreCallValidateCmdDrawIndexed(dev_data, commandBuffer, true, VK_PIPELINE_BIND_POINT_GRAPHICS, &cb_state,
7224ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                              "vkCmdDrawIndexed()");
7225b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7226ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    if (!skip) {
72274a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDrawIndexed(commandBuffer, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
7228ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis        lock.lock();
7229ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDrawIndexed(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS);
7230ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis        lock.unlock();
7231ac4451d7e5da96a3a5d51e613c583c057aee9cf4Tobin Ehlis    }
72325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
72335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7234ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDrawIndirect(layer_data *dev_data, VkCommandBuffer cmd_buffer, VkBuffer buffer, bool indexed,
7235ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                           VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state, BUFFER_STATE **buffer_state,
7236ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                           const char *caller) {
7237315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    bool skip =
7238315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAWINDIRECT, cb_state, caller, VK_QUEUE_GRAPHICS_BIT,
7239315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            VALIDATION_ERROR_1aa02415, VALIDATION_ERROR_1aa00017, VALIDATION_ERROR_1aa003cc);
72409a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *buffer_state = GetBufferState(dev_data, buffer);
7241315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= ValidateMemoryIsBoundToBuffer(dev_data, *buffer_state, caller, VALIDATION_ERROR_1aa003b4);
724213c4316d0072cbc5bf3cd729abef4d114f3c96edMark Lobodzinski    // TODO: If the drawIndirectFirstInstance feature is not enabled, all the firstInstance members of the
724313c4316d0072cbc5bf3cd729abef4d114f3c96edMark Lobodzinski    // VkDrawIndirectCommand structures accessed by this command must be 0, which will require access to the contents of 'buffer'.
7244d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    return skip;
7245d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis}
7246d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis
7247ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDrawIndirect(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
7248ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                          BUFFER_STATE *buffer_state) {
7249b68b13ed4952bce61f6ebb0023542660c26b0562Chris Forbes    UpdateStateCmdDrawType(dev_data, cb_state, bind_point, CMD_DRAWINDIRECT);
7250d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    AddCommandBufferBindingBuffer(dev_data, cb_state, buffer_state);
7251d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis}
7252d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis
7253bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count,
7254bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           uint32_t stride) {
725556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7256d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
7257d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    BUFFER_STATE *buffer_state = nullptr;
7258b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7259872a2f0ca3ffdeddfa7483e777191fa64b853892Tony Barbour    bool skip = PreCallValidateCmdDrawIndirect(dev_data, commandBuffer, buffer, false, VK_PIPELINE_BIND_POINT_GRAPHICS, &cb_state,
7260ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                               &buffer_state, "vkCmdDrawIndirect()");
7261b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7262d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    if (!skip) {
72634a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDrawIndirect(commandBuffer, buffer, offset, count, stride);
7264d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis        lock.lock();
7265ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDrawIndirect(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, buffer_state);
7266d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis        lock.unlock();
7267d6df438f6e5bf5142a66c857e5c84dd402451242Tobin Ehlis    }
72685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
72695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7270ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDrawIndexedIndirect(layer_data *dev_data, VkCommandBuffer cmd_buffer, VkBuffer buffer, bool indexed,
7271ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                  VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state,
7272ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                  BUFFER_STATE **buffer_state, const char *caller) {
7273315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    bool skip =
7274315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DRAWINDEXEDINDIRECT, cb_state, caller,
7275315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1a602415, VALIDATION_ERROR_1a600017, VALIDATION_ERROR_1a600434);
72769a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *buffer_state = GetBufferState(dev_data, buffer);
7277315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= ValidateMemoryIsBoundToBuffer(dev_data, *buffer_state, caller, VALIDATION_ERROR_1a60041c);
727813c4316d0072cbc5bf3cd729abef4d114f3c96edMark Lobodzinski    // TODO: If the drawIndirectFirstInstance feature is not enabled, all the firstInstance members of the
727913c4316d0072cbc5bf3cd729abef4d114f3c96edMark Lobodzinski    // VkDrawIndexedIndirectCommand structures accessed by this command must be 0, which will require access to the contents of
728013c4316d0072cbc5bf3cd729abef4d114f3c96edMark Lobodzinski    // 'buffer'.
72810c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    return skip;
72820c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis}
72830c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis
7284ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDrawIndexedIndirect(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
7285ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                 BUFFER_STATE *buffer_state) {
7286b68b13ed4952bce61f6ebb0023542660c26b0562Chris Forbes    UpdateStateCmdDrawType(dev_data, cb_state, bind_point, CMD_DRAWINDEXEDINDIRECT);
72870c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    AddCommandBufferBindingBuffer(dev_data, cb_state, buffer_state);
72880c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis}
72890c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis
7290bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
7291bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                  uint32_t count, uint32_t stride) {
729256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
72930c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
72940c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    BUFFER_STATE *buffer_state = nullptr;
7295b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
72960c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    bool skip = PreCallValidateCmdDrawIndexedIndirect(dev_data, commandBuffer, buffer, true, VK_PIPELINE_BIND_POINT_GRAPHICS,
7297ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                      &cb_state, &buffer_state, "vkCmdDrawIndexedIndirect()");
7298b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
72990c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    if (!skip) {
73004a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDrawIndexedIndirect(commandBuffer, buffer, offset, count, stride);
73010c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis        lock.lock();
7302ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDrawIndexedIndirect(dev_data, cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, buffer_state);
73030c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis        lock.unlock();
73040c9ad626388bcde527db8d89829c45ebf0a94723Tobin Ehlis    }
73055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
73065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7307ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDispatch(layer_data *dev_data, VkCommandBuffer cmd_buffer, bool indexed,
7308ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                       VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state, const char *caller) {
7309baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    return ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DISPATCH, cb_state, caller, VK_QUEUE_COMPUTE_BIT,
7310315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                               VALIDATION_ERROR_19c02415, VALIDATION_ERROR_19c00017, VALIDATION_ERROR_UNDEFINED);
731125d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis}
731225d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis
7313ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDispatch(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point) {
7314ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawDispatchType(dev_data, cb_state, bind_point, CMD_DISPATCH);
731525d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis}
731625d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis
731789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z) {
731856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
731925d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
7320b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7321ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    bool skip =
7322ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PreCallValidateCmdDispatch(dev_data, commandBuffer, false, VK_PIPELINE_BIND_POINT_COMPUTE, &cb_state, "vkCmdDispatch()");
7323b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
732425d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis    if (!skip) {
73254a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDispatch(commandBuffer, x, y, z);
732625d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis        lock.lock();
7327ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDispatch(dev_data, cb_state, VK_PIPELINE_BIND_POINT_COMPUTE);
732825d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis        lock.unlock();
732925d3241067a529052f120867aa4c6161047cdb60Tobin Ehlis    }
73305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
73315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7332ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic bool PreCallValidateCmdDispatchIndirect(layer_data *dev_data, VkCommandBuffer cmd_buffer, VkBuffer buffer, bool indexed,
7333ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                               VkPipelineBindPoint bind_point, GLOBAL_CB_NODE **cb_state,
7334ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                               BUFFER_STATE **buffer_state, const char *caller) {
7335baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    bool skip =
7336baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        ValidateCmdDrawType(dev_data, cmd_buffer, indexed, bind_point, CMD_DISPATCHINDIRECT, cb_state, caller, VK_QUEUE_COMPUTE_BIT,
7337315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            VALIDATION_ERROR_1a002415, VALIDATION_ERROR_1a000017, VALIDATION_ERROR_UNDEFINED);
73389a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    *buffer_state = GetBufferState(dev_data, buffer);
7339315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= ValidateMemoryIsBoundToBuffer(dev_data, *buffer_state, caller, VALIDATION_ERROR_1a000322);
734079c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    return skip;
734179c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis}
734279c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis
7343ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlisstatic void PostCallRecordCmdDispatchIndirect(layer_data *dev_data, GLOBAL_CB_NODE *cb_state, VkPipelineBindPoint bind_point,
7344ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                              BUFFER_STATE *buffer_state) {
7345ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis    UpdateStateCmdDrawDispatchType(dev_data, cb_state, bind_point, CMD_DISPATCHINDIRECT);
734679c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    AddCommandBufferBindingBuffer(dev_data, cb_state, buffer_state);
734779c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis}
734879c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis
7349bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset) {
735056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
735179c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    GLOBAL_CB_NODE *cb_state = nullptr;
735279c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    BUFFER_STATE *buffer_state = nullptr;
7353b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
73547433ab60c7ff16d37edb0f8b17b606ccd363e210Tobin Ehlis    bool skip = PreCallValidateCmdDispatchIndirect(dev_data, commandBuffer, buffer, false, VK_PIPELINE_BIND_POINT_COMPUTE,
7355ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis                                                   &cb_state, &buffer_state, "vkCmdDispatchIndirect()");
7356b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
735779c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    if (!skip) {
73584a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdDispatchIndirect(commandBuffer, buffer, offset);
735979c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis        lock.lock();
7360ffa1c08650c9dbe798f25b88bef4b28d33d57b01Tobin Ehlis        PostCallRecordCmdDispatchIndirect(dev_data, cb_state, VK_PIPELINE_BIND_POINT_COMPUTE, buffer_state);
736179c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis        lock.unlock();
736279c66dcd1e0db7de8556bce6deb782a150c77b92Tobin Ehlis    }
73635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
73645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
736589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
736689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                         uint32_t regionCount, const VkBufferCopy *pRegions) {
7367c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7368b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7369ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
7370c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski    auto cb_node = GetCBNode(device_data, commandBuffer);
7371c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski    auto src_buffer_state = GetBufferState(device_data, srcBuffer);
7372c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski    auto dst_buffer_state = GetBufferState(device_data, dstBuffer);
7373593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
7374c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski    if (cb_node && src_buffer_state && dst_buffer_state) {
7375c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski        bool skip = PreCallValidateCmdCopyBuffer(device_data, cb_node, src_buffer_state, dst_buffer_state);
7376c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski        if (!skip) {
7377c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski            PreCallRecordCmdCopyBuffer(device_data, cb_node, src_buffer_state, dst_buffer_state);
7378c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski            lock.unlock();
7379c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski            device_data->dispatch_table.CmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, regionCount, pRegions);
7380c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski        }
7381ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
7382c40a396f8341e1e1e5fdf1d023a987b874763446Mark Lobodzinski        lock.unlock();
7383ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
73845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
73855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
73865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7387bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
7388bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
7389bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        const VkImageCopy *pRegions) {
73906a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    bool skip = false;
73916a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7392b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7393249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis
73946a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    auto cb_node = GetCBNode(device_data, commandBuffer);
73956a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    auto src_image_state = GetImageState(device_data, srcImage);
73966a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski    auto dst_image_state = GetImageState(device_data, dstImage);
73971facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (cb_node && src_image_state && dst_image_state) {
73986a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski        skip = PreCallValidateCmdCopyImage(device_data, cb_node, src_image_state, dst_image_state, regionCount, pRegions,
73996a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski                                           srcImageLayout, dstImageLayout);
74006a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski        if (!skip) {
7401a07ae8bd5f566eb9b073498dd4280efdb0b838b9Tobin Ehlis            PreCallRecordCmdCopyImage(device_data, cb_node, src_image_state, dst_image_state, regionCount, pRegions, srcImageLayout,
7402a07ae8bd5f566eb9b073498dd4280efdb0b838b9Tobin Ehlis                                      dstImageLayout);
74036a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski            lock.unlock();
74046a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski            device_data->dispatch_table.CmdCopyImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
74056a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski                                                     pRegions);
74065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7407249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis    } else {
74086a7544432041a5ced84128597a44c55dfde2105cMark Lobodzinski        lock.unlock();
7409249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis        assert(0);
74105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
74115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
74125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7413eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski// Validate that an image's sampleCount matches the requirement for a specific API call
741460568995aca225f81acda8ce40cfabbea2c19397Mark Lobodzinskibool ValidateImageSampleCount(layer_data *dev_data, IMAGE_STATE *image_state, VkSampleCountFlagBits sample_count,
741560568995aca225f81acda8ce40cfabbea2c19397Mark Lobodzinski                              const char *location, UNIQUE_VALIDATION_ERROR_CODE msgCode) {
7416eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski    bool skip = false;
74171facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (image_state->createInfo.samples != sample_count) {
74189b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus        skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
74199b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       HandleToUint64(image_state->image), 0, msgCode, "DS",
74209b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       "%s for image 0x%" PRIxLEAST64 " was created with a sample count of %s but must be %s. %s", location,
74219b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       HandleToUint64(image_state->image), string_VkSampleCountFlagBits(image_state->createInfo.samples),
74229b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                       string_VkSampleCountFlagBits(sample_count), validation_error_map[msgCode]);
7423eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski    }
7424eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski    return skip;
7425eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski}
7426eebf670a2f04c402f2875f85aa4f889b06db48fcMark Lobodzinski
7427bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
7428bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
7429bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                        const VkImageBlit *pRegions, VkFilter filter) {
743056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7431b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7432593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
74339a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
74349a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto src_image_state = GetImageState(dev_data, srcImage);
74359a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto dst_image_state = GetImageState(dev_data, dstImage);
74360dc51740dbd7b9f0ba7c071e0bf96f63d6d48c85Mark Lobodzinski
7437055112ec99304db71d55b69a60e1da14e8af8f60Mark Lobodzinski    bool skip = PreCallValidateCmdBlitImage(dev_data, cb_node, src_image_state, dst_image_state, regionCount, pRegions, filter);
74380dc51740dbd7b9f0ba7c071e0bf96f63d6d48c85Mark Lobodzinski
7439dca02371c9531e7a9a2a51decae1db4d297862c4Mark Lobodzinski    if (!skip) {
7440eebd811afd800663f15fda8fc71bc203a03fe294Mark Lobodzinski        PreCallRecordCmdBlitImage(dev_data, cb_node, src_image_state, dst_image_state);
7441eebd811afd800663f15fda8fc71bc203a03fe294Mark Lobodzinski        lock.unlock();
74424a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdBlitImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
74434a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                              pRegions, filter);
74440dc51740dbd7b9f0ba7c071e0bf96f63d6d48c85Mark Lobodzinski    }
74455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
74465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7447bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage,
7448bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                VkImageLayout dstImageLayout, uint32_t regionCount,
7449bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                const VkBufferImageCopy *pRegions) {
7450940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7451b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7452940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    bool skip = false;
7453940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto cb_node = GetCBNode(device_data, commandBuffer);
7454940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto src_buffer_state = GetBufferState(device_data, srcBuffer);
7455940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto dst_image_state = GetImageState(device_data, dstImage);
7456940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    if (cb_node && src_buffer_state && dst_image_state) {
7457940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski        skip = PreCallValidateCmdCopyBufferToImage(device_data, dstImageLayout, cb_node, src_buffer_state, dst_image_state,
745871c68ce753146a69508694cfc5fc2dcfa08c692eMark Lobodzinski                                                        regionCount, pRegions, "vkCmdCopyBufferToImage()");
7459ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
7460d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski        lock.unlock();
7461ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
7462e4d82c37d6c861b388dbc80297c18d6255858cb4Dave Houlton        // TODO: report VU01244 here, or put in object tracker?
74635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7464940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    if (!skip) {
7465a07ae8bd5f566eb9b073498dd4280efdb0b838b9Tobin Ehlis        PreCallRecordCmdCopyBufferToImage(device_data, cb_node, src_buffer_state, dst_image_state, regionCount, pRegions,
7466a07ae8bd5f566eb9b073498dd4280efdb0b838b9Tobin Ehlis                                          dstImageLayout);
7467d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski        lock.unlock();
7468940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski        device_data->dispatch_table.CmdCopyBufferToImage(commandBuffer, srcBuffer, dstImage, dstImageLayout, regionCount, pRegions);
7469d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski    }
74705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
74715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7472bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
7473bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy *pRegions) {
7474940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    bool skip = false;
7475940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7476b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7477593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
7478940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto cb_node = GetCBNode(device_data, commandBuffer);
7479940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto src_image_state = GetImageState(device_data, srcImage);
7480940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    auto dst_buffer_state = GetBufferState(device_data, dstBuffer);
7481940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    if (cb_node && src_image_state && dst_buffer_state) {
7482940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski        skip = PreCallValidateCmdCopyImageToBuffer(device_data, srcImageLayout, cb_node, src_image_state, dst_buffer_state,
748371c68ce753146a69508694cfc5fc2dcfa08c692eMark Lobodzinski                                                        regionCount, pRegions, "vkCmdCopyImageToBuffer()");
7484ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
7485d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski        lock.unlock();
7486ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
7487e4d82c37d6c861b388dbc80297c18d6255858cb4Dave Houlton        // TODO: report VU01262 here, or put in object tracker?
74885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7489940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski    if (!skip) {
7490a07ae8bd5f566eb9b073498dd4280efdb0b838b9Tobin Ehlis        PreCallRecordCmdCopyImageToBuffer(device_data, cb_node, src_image_state, dst_buffer_state, regionCount, pRegions,
7491a07ae8bd5f566eb9b073498dd4280efdb0b838b9Tobin Ehlis                                          srcImageLayout);
7492d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski        lock.unlock();
7493940f70f1340803d185c67633b05ef048d277952eMark Lobodzinski        device_data->dispatch_table.CmdCopyImageToBuffer(commandBuffer, srcImage, srcImageLayout, dstBuffer, regionCount, pRegions);
7494d5cde34b61eb694c6fe1d5e53de61bb87bf6936aMark Lobodzinski    }
74955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
74965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7497bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
7498bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           VkDeviceSize dataSize, const uint32_t *pData) {
74993251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
750056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7501b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7502593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
75039a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
75049a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto dst_buff_state = GetBufferState(dev_data, dstBuffer);
75055cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (cb_node && dst_buff_state) {
7506315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateMemoryIsBoundToBuffer(dev_data, dst_buff_state, "vkCmdUpdateBuffer()", VALIDATION_ERROR_1e400046);
7507ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Update bindings between buffer and cmd buffer
75085cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        AddCommandBufferBindingBuffer(dev_data, cb_node, dst_buff_state);
7509ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Validate that DST buffer has correct usage flags set
7510315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateBufferUsageFlags(dev_data, dst_buff_state, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true,
7511315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                         VALIDATION_ERROR_1e400044, "vkCmdUpdateBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
7512e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
75135cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            SetBufferMemoryValid(dev_data, dst_buff_state, true);
7514e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
75155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        };
75169f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
7517593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
7518315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |=
7519315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            ValidateCmdQueueFlags(dev_data, cb_node, "vkCmdUpdateBuffer()",
7520315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                  VK_QUEUE_TRANSFER_BIT | VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, VALIDATION_ERROR_1e402415);
75213251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_node, CMD_UPDATEBUFFER, "vkCmdUpdateBuffer()");
75221ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(cb_node, CMD_UPDATEBUFFER);
7523315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= insideRenderPass(dev_data, cb_node, "vkCmdUpdateBuffer()", VALIDATION_ERROR_1e400017);
7524ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
7525ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
75265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7527b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
75283251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdUpdateBuffer(commandBuffer, dstBuffer, dstOffset, dataSize, pData);
75295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
75305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7531bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
7532bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         VkDeviceSize size, uint32_t data) {
753323bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7534b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
753523bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski    auto cb_node = GetCBNode(device_data, commandBuffer);
753623bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski    auto buffer_state = GetBufferState(device_data, dstBuffer);
7537593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
753823bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski    if (cb_node && buffer_state) {
753923bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski        bool skip = PreCallValidateCmdFillBuffer(device_data, cb_node, buffer_state);
754023bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski        if (!skip) {
754123bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski            PreCallRecordCmdFillBuffer(device_data, cb_node, buffer_state);
754223bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski            lock.unlock();
754323bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski            device_data->dispatch_table.CmdFillBuffer(commandBuffer, dstBuffer, dstOffset, size, data);
754423bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski        }
7545ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
754623bb5a2fd221f6788daf2dd976bf19a5e9b20fb9Mark Lobodzinski        lock.unlock();
7547ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
75485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
75495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
75505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
75514028af23e688ab5730f48ab2244dd042e2eefaedMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount,
75524028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski                                               const VkClearAttachment *pAttachments, uint32_t rectCount,
75534028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski                                               const VkClearRect *pRects) {
75544028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski    bool skip = false;
755556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
75564028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski    {
75574028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski        std::lock_guard<std::mutex> lock(global_lock);
75584028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski        skip = PreCallValidateCmdClearAttachments(dev_data, commandBuffer, attachmentCount, pAttachments, rectCount, pRects);
75594028af23e688ab5730f48ab2244dd042e2eefaedMark Lobodzinski    }
7560cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdClearAttachments(commandBuffer, attachmentCount, pAttachments, rectCount, pRects);
75615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
75625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
75630482c55760707900fcd072f6895c121bcf055f6eMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
75640482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski                                              const VkClearColorValue *pColor, uint32_t rangeCount,
75650482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski                                              const VkImageSubresourceRange *pRanges) {
756656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7567b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
75680482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski
75690482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    bool skip = PreCallValidateCmdClearColorImage(dev_data, commandBuffer, image, imageLayout, rangeCount, pRanges);
75700482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    if (!skip) {
75710482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        PreCallRecordCmdClearImage(dev_data, commandBuffer, image, imageLayout, rangeCount, pRanges, CMD_CLEARCOLORIMAGE);
75720482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        lock.unlock();
75730482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        dev_data->dispatch_table.CmdClearColorImage(commandBuffer, image, imageLayout, pColor, rangeCount, pRanges);
75740482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    }
75750482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski}
75760482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski
75770482c55760707900fcd072f6895c121bcf055f6eMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
75780482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski                                                     const VkClearDepthStencilValue *pDepthStencil, uint32_t rangeCount,
75790482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski                                                     const VkImageSubresourceRange *pRanges) {
758056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
75810482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    std::unique_lock<std::mutex> lock(global_lock);
75820482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski
75830482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    bool skip = PreCallValidateCmdClearDepthStencilImage(dev_data, commandBuffer, image, imageLayout, rangeCount, pRanges);
75840482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski    if (!skip) {
75850482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        PreCallRecordCmdClearImage(dev_data, commandBuffer, image, imageLayout, rangeCount, pRanges, CMD_CLEARDEPTHSTENCILIMAGE);
75860482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        lock.unlock();
75870482c55760707900fcd072f6895c121bcf055f6eMark Lobodzinski        dev_data->dispatch_table.CmdClearDepthStencilImage(commandBuffer, image, imageLayout, pDepthStencil, rangeCount, pRanges);
75887f8aa8f5abceedbb599ef69af1dfbb38c0df2660Slawomir Cygan    }
75895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
75905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7591bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
7592bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
7593bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           const VkImageResolve *pRegions) {
759456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7595b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
7596593c857d8db57cf9ae2c590b75e22dadd51bd3d4Tobin Ehlis
75979a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
75989a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto src_image_state = GetImageState(dev_data, srcImage);
75999a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto dst_image_state = GetImageState(dev_data, dstImage);
760009fe5ac5edaec7f0dbcc9fd696e68194569aea89Mark Lobodzinski
760125f7873c9ce3ed39d18bba8750d7538905e150dfMark Lobodzinski    bool skip = PreCallValidateCmdResolveImage(dev_data, cb_node, src_image_state, dst_image_state, regionCount, pRegions);
760209fe5ac5edaec7f0dbcc9fd696e68194569aea89Mark Lobodzinski
760309fe5ac5edaec7f0dbcc9fd696e68194569aea89Mark Lobodzinski    if (!skip) {
76046c0400e625554ce7fddb833eeace0de19cfcc965Mark Lobodzinski        PreCallRecordCmdResolveImage(dev_data, cb_node, src_image_state, dst_image_state);
76056c0400e625554ce7fddb833eeace0de19cfcc965Mark Lobodzinski        lock.unlock();
76064a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdResolveImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
76074a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                 pRegions);
760809fe5ac5edaec7f0dbcc9fd696e68194569aea89Mark Lobodzinski    }
76095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
76105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7611a8d1e377bdeaf61a3209cb997502da4356a185bbMike WeiblenVKAPI_ATTR void VKAPI_CALL GetImageSubresourceLayout(VkDevice device, VkImage image, const VkImageSubresource *pSubresource,
7612a8d1e377bdeaf61a3209cb997502da4356a185bbMike Weiblen                                                     VkSubresourceLayout *pLayout) {
7613a8d1e377bdeaf61a3209cb997502da4356a185bbMike Weiblen    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
7614a8d1e377bdeaf61a3209cb997502da4356a185bbMike Weiblen
7615a8d1e377bdeaf61a3209cb997502da4356a185bbMike Weiblen    bool skip = PreCallValidateGetImageSubresourceLayout(device_data, image, pSubresource);
7616a8d1e377bdeaf61a3209cb997502da4356a185bbMike Weiblen    if (!skip) {
7617b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski        device_data->dispatch_table.GetImageSubresourceLayout(device, image, pSubresource, pLayout);
7618b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski    }
7619b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski}
7620b06379a335598a3d8c53c694e875dda19eeab612Mark Lobodzinski
7621b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentinebool setEventStageMask(VkQueue queue, VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
762256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
76239a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
7624b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    if (pCB) {
7625b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        pCB->eventToStageMap[event] = stageMask;
7626b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
7627b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    auto queue_data = dev_data->queueMap.find(queue);
7628b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    if (queue_data != dev_data->queueMap.end()) {
7629b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        queue_data->second.eventToStageMap[event] = stageMask;
7630b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
7631b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    return false;
7632b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine}
7633b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine
7634bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdSetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
76353251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
763656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7637b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
76389a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
76395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
76403251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdSetEvent()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
7641315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                      VALIDATION_ERROR_1d402415);
76423251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_SETEVENT, "vkCmdSetEvent()");
76431ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_SETEVENT);
7644315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= insideRenderPass(dev_data, pCB, "vkCmdSetEvent()", VALIDATION_ERROR_1d400017);
7645315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateStageMaskGsTsEnables(dev_data, stageMask, "vkCmdSetEvent()", VALIDATION_ERROR_1d4008fc,
7646315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                             VALIDATION_ERROR_1d4008fe);
76479a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto event_state = GetEventNode(dev_data, event);
76484710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        if (event_state) {
76499b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus            addCommandBufferBinding(&event_state->cb_bindings, {HandleToUint64(event), kVulkanObjectTypeEvent}, pCB);
76504710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis            event_state->cb_bindings.insert(pCB);
7651ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis        }
76525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->events.push_back(event);
7653c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine        if (!pCB->waitedEvents.count(event)) {
7654c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine            pCB->writeEventsBeforeWait.push_back(event);
7655c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine        }
7656b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        std::function<bool(VkQueue)> eventUpdate =
7657b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            std::bind(setEventStageMask, std::placeholders::_1, commandBuffer, event, stageMask);
7658b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        pCB->eventUpdates.push_back(eventUpdate);
76595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7660b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
76613251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdSetEvent(commandBuffer, event, stageMask);
76625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
76635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7664bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdResetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
76653251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
766656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7667b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
76689a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
76695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
76703251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdResetEvent()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
7671315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                      VALIDATION_ERROR_1c402415);
76723251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_RESETEVENT, "vkCmdResetEvent()");
76731ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_RESETEVENT);
7674315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= insideRenderPass(dev_data, pCB, "vkCmdResetEvent()", VALIDATION_ERROR_1c400017);
7675315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateStageMaskGsTsEnables(dev_data, stageMask, "vkCmdResetEvent()", VALIDATION_ERROR_1c400904,
7676315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                             VALIDATION_ERROR_1c400906);
76779a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto event_state = GetEventNode(dev_data, event);
76784710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        if (event_state) {
76799b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus            addCommandBufferBinding(&event_state->cb_bindings, {HandleToUint64(event), kVulkanObjectTypeEvent}, pCB);
76804710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis            event_state->cb_bindings.insert(pCB);
7681ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis        }
76825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->events.push_back(event);
7683c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine        if (!pCB->waitedEvents.count(event)) {
7684c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine            pCB->writeEventsBeforeWait.push_back(event);
7685c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine        }
7686315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        // TODO : Add check for VALIDATION_ERROR_32c008f8
7687b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        std::function<bool(VkQueue)> eventUpdate =
7688b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            std::bind(setEventStageMask, std::placeholders::_1, commandBuffer, event, VkPipelineStageFlags(0));
7689b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        pCB->eventUpdates.push_back(eventUpdate);
76905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7691b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
76923251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdResetEvent(commandBuffer, event, stageMask);
76935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
76945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7695e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool ValidateBarriers(const char *funcName, VkCommandBuffer cmdBuffer, uint32_t memBarrierCount,
7696e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                             const VkMemoryBarrier *pMemBarriers, uint32_t bufferBarrierCount,
7697e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                             const VkBufferMemoryBarrier *pBufferMemBarriers, uint32_t imageMemBarrierCount,
7698e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                             const VkImageMemoryBarrier *pImageMemBarriers) {
7699a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis    bool skip = false;
770056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(cmdBuffer), layer_data_map);
77019a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, cmdBuffer);
77025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB->activeRenderPass && memBarrierCount) {
7703ee691f5c5fa87aac3750454d2bca2cb582e4e817Chris Forbes        if (!pCB->activeRenderPass->hasSelfDependency[pCB->activeSubpass]) {
7704df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
77059b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(cmdBuffer), __LINE__, DRAWSTATE_INVALID_BARRIER, "DS",
7706cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s: Barriers cannot be set during subpass %d "
7707cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "with no self dependency specified.",
7708a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            funcName, pCB->activeSubpass);
77095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
77105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
77115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < imageMemBarrierCount; ++i) {
77125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto mem_barrier = &pImageMemBarriers[i];
77138f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski        auto image_data = GetImageState(dev_data, mem_barrier->image);
77148f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski        if (image_data) {
77158f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski            uint32_t src_q_f_index = mem_barrier->srcQueueFamilyIndex;
77168f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski            uint32_t dst_q_f_index = mem_barrier->dstQueueFamilyIndex;
77178f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski            if (image_data->createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) {
77188f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                // srcQueueFamilyIndex and dstQueueFamilyIndex must both
77198f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                // be VK_QUEUE_FAMILY_IGNORED
77208f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                if ((src_q_f_index != VK_QUEUE_FAMILY_IGNORED) || (dst_q_f_index != VK_QUEUE_FAMILY_IGNORED)) {
77218f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
77229b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(cmdBuffer), __LINE__,
77239b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    DRAWSTATE_INVALID_QUEUE_INDEX, "DS", "%s: Image Barrier for image 0x%" PRIx64
77249b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                                                         " was created with sharingMode of "
77259b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                                                         "VK_SHARING_MODE_CONCURRENT. Src and dst "
77269b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                                                         "queueFamilyIndices must be VK_QUEUE_FAMILY_IGNORED.",
77279b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    funcName, HandleToUint64(mem_barrier->image));
77288f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                }
77298f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski            } else {
77308f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                // Sharing mode is VK_SHARING_MODE_EXCLUSIVE. srcQueueFamilyIndex and
77318f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                // dstQueueFamilyIndex must either both be VK_QUEUE_FAMILY_IGNORED,
77328f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                // or both be a valid queue family
77338f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                if (((src_q_f_index == VK_QUEUE_FAMILY_IGNORED) || (dst_q_f_index == VK_QUEUE_FAMILY_IGNORED)) &&
77348f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                    (src_q_f_index != dst_q_f_index)) {
77358f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
77369b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(cmdBuffer), __LINE__,
77379b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    DRAWSTATE_INVALID_QUEUE_INDEX, "DS", "%s: Image 0x%" PRIx64
77389b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                                                         " was created with sharingMode "
77399b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                                                         "of VK_SHARING_MODE_EXCLUSIVE. If one of src- or "
77409b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                                                         "dstQueueFamilyIndex is VK_QUEUE_FAMILY_IGNORED, both "
77419b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                                                         "must be.",
77429b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    funcName, HandleToUint64(mem_barrier->image));
77438f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                } else if (((src_q_f_index != VK_QUEUE_FAMILY_IGNORED) && (dst_q_f_index != VK_QUEUE_FAMILY_IGNORED)) &&
77448f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                           ((src_q_f_index >= dev_data->phys_dev_properties.queue_family_properties.size()) ||
77458f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                            (dst_q_f_index >= dev_data->phys_dev_properties.queue_family_properties.size()))) {
77468f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
77479b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(cmdBuffer), __LINE__,
77488f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                                    DRAWSTATE_INVALID_QUEUE_INDEX, "DS",
77498f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                                    "%s: Image 0x%" PRIx64
77508f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                                    " was created with sharingMode "
77518f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                                    "of VK_SHARING_MODE_EXCLUSIVE, but srcQueueFamilyIndex %d"
77528f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                                    " or dstQueueFamilyIndex %d is greater than " PRINTF_SIZE_T_SPECIFIER
77538f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                                    "queueFamilies crated for this device.",
77549b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    funcName, HandleToUint64(mem_barrier->image), src_q_f_index, dst_q_f_index,
77558f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski                                    dev_data->phys_dev_properties.queue_family_properties.size());
77565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
77575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
77588f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski        }
77595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
77608f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski        if (mem_barrier->oldLayout != mem_barrier->newLayout) {
77618f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski            if (pCB->activeRenderPass) {
77629b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                skip |=
77639b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
7764315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(cmdBuffer), __LINE__, VALIDATION_ERROR_1b80093a, "DS",
77659b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "%s: As the Image Barrier for image 0x%" PRIx64
77669b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            " is being executed within a render pass instance, oldLayout must equal newLayout yet they are "
77679b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "%s and %s. %s",
77689b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            funcName, HandleToUint64(mem_barrier->image), string_VkImageLayout(mem_barrier->oldLayout),
7769315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            string_VkImageLayout(mem_barrier->newLayout), validation_error_map[VALIDATION_ERROR_1b80093a]);
7770d678ec4f57d80aa89c24562e9ffe941d8d69e455Tony Barbour            }
77718f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski            skip |= ValidateMaskBitsFromLayouts(dev_data, cmdBuffer, mem_barrier->srcAccessMask, mem_barrier->oldLayout, "Source");
77728f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski            skip |= ValidateMaskBitsFromLayouts(dev_data, cmdBuffer, mem_barrier->dstAccessMask, mem_barrier->newLayout, "Dest");
77738f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski        }
77748f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski        if (mem_barrier->newLayout == VK_IMAGE_LAYOUT_UNDEFINED || mem_barrier->newLayout == VK_IMAGE_LAYOUT_PREINITIALIZED) {
77758f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
77769b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(cmdBuffer), __LINE__, DRAWSTATE_INVALID_BARRIER, "DS",
7777df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "%s: Image Layout cannot be transitioned to UNDEFINED or "
7778df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "PREINITIALIZED.",
7779df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            funcName);
77808f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski        }
77818f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski        if (image_data) {
77828f3c2a27e8e6feeb21d6be3b6f9f8d0606f67457Mark Lobodzinski            auto aspect_mask = mem_barrier->subresourceRange.aspectMask;
77832044b110851e8f1b75d6d406a0c88612476c63dbChris Forbes            skip |= ValidateImageAspectMask(dev_data, image_data->image, image_data->createInfo.format, aspect_mask, funcName);
778495b7894efd5e101e410da92fc697429aec3ffa7bMark Lobodzinski
778523c5a2092f724fef497a5c87a489f32c8fa51e58Petr Kraus            std::string param_name = "pImageMemoryBarriers[" + std::to_string(i) + "].subresourceRange";
7786dab32891b91206a5bef7a3929b781e44fc1b7268Petr Kraus            skip |= ValidateImageSubresourceRange(dev_data, image_data, false, mem_barrier->subresourceRange, funcName,
778723c5a2092f724fef497a5c87a489f32c8fa51e58Petr Kraus                                                  param_name.c_str());
77885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
77895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
77902044b110851e8f1b75d6d406a0c88612476c63dbChris Forbes
77915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < bufferBarrierCount; ++i) {
77925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto mem_barrier = &pBufferMemBarriers[i];
77935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (pCB->activeRenderPass) {
7794df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
77959b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(cmdBuffer), __LINE__, DRAWSTATE_INVALID_BARRIER, "DS",
7796df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "%s: Buffer Barriers cannot be used during a render pass.", funcName);
77975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7798cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!mem_barrier) continue;
77995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
78005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Validate buffer barrier queue family indices
78015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if ((mem_barrier->srcQueueFamilyIndex != VK_QUEUE_FAMILY_IGNORED &&
7802b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis             mem_barrier->srcQueueFamilyIndex >= dev_data->phys_dev_properties.queue_family_properties.size()) ||
78035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            (mem_barrier->dstQueueFamilyIndex != VK_QUEUE_FAMILY_IGNORED &&
7804b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis             mem_barrier->dstQueueFamilyIndex >= dev_data->phys_dev_properties.queue_family_properties.size())) {
7805df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
78069b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(cmdBuffer), __LINE__, DRAWSTATE_INVALID_QUEUE_INDEX, "DS",
7807cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "%s: Buffer Barrier 0x%" PRIx64
7808cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            " has QueueFamilyIndex greater "
7809a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            "than the number of QueueFamilies (" PRINTF_SIZE_T_SPECIFIER ") for this device.",
78109b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            funcName, HandleToUint64(mem_barrier->buffer),
7811a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis                            dev_data->phys_dev_properties.queue_family_properties.size());
78125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
78135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
78149a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto buffer_state = GetBufferState(dev_data, mem_barrier->buffer);
78155cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        if (buffer_state) {
78165cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            auto buffer_size = buffer_state->requirements.size;
78175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (mem_barrier->offset >= buffer_size) {
78189b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
78199b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(cmdBuffer), __LINE__,
78209b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                DRAWSTATE_INVALID_BARRIER, "DS", "%s: Buffer Barrier 0x%" PRIx64 " has offset 0x%" PRIx64
78219b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                                                 " which is not less than total size 0x%" PRIx64 ".",
78229b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                funcName, HandleToUint64(mem_barrier->buffer), HandleToUint64(mem_barrier->offset),
78239b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(buffer_size));
7824df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            } else if (mem_barrier->size != VK_WHOLE_SIZE && (mem_barrier->offset + mem_barrier->size > buffer_size)) {
7825df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                skip |=
7826df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
78279b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(cmdBuffer), __LINE__, DRAWSTATE_INVALID_BARRIER, "DS",
7828df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "%s: Buffer Barrier 0x%" PRIx64 " has offset 0x%" PRIx64 " and size 0x%" PRIx64
7829df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            " whose sum is greater than total size 0x%" PRIx64 ".",
78309b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            funcName, HandleToUint64(mem_barrier->buffer), HandleToUint64(mem_barrier->offset),
78319b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(mem_barrier->size), HandleToUint64(buffer_size));
78325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
78335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
78345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7835a4a1923d21087ded8e990190acd6752264712319Tobin Ehlis    return skip;
78365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
78375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
7838bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskibool validateEventStageMask(VkQueue queue, GLOBAL_CB_NODE *pCB, uint32_t eventCount, size_t firstEventIndex,
7839bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            VkPipelineStageFlags sourceStageMask) {
78403251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
7841b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    VkPipelineStageFlags stageMask = 0;
784256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
7843b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    for (uint32_t i = 0; i < eventCount; ++i) {
78442ab14387df9b890fe4b13494ea249dd03cf898d2Chris Forbes        auto event = pCB->events[firstEventIndex + i];
7845b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        auto queue_data = dev_data->queueMap.find(queue);
7846cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (queue_data == dev_data->queueMap.end()) return false;
78472ab14387df9b890fe4b13494ea249dd03cf898d2Chris Forbes        auto event_data = queue_data->second.eventToStageMap.find(event);
7848b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        if (event_data != queue_data->second.eventToStageMap.end()) {
7849b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            stageMask |= event_data->second;
7850b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        } else {
78519a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto global_event_data = GetEventNode(dev_data, event);
78529556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis            if (!global_event_data) {
78533251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT,
78549b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(event), __LINE__, DRAWSTATE_INVALID_EVENT, "DS",
78559b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "Event 0x%" PRIx64 " cannot be waited on if it has never been set.", HandleToUint64(event));
7856b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            } else {
78579556936067fd0c4eb74c4a13631bc163b154faedTobin Ehlis                stageMask |= global_event_data->stageMask;
7858b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine            }
7859b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine        }
7860b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
7861c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    // TODO: Need to validate that host_bit is only set if set event is called
7862c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    // but set event can be called at any time.
7863c1eb2a3736e03aaa15b849d217fd963021dc9780Michael Lentine    if (sourceStageMask != stageMask && sourceStageMask != (stageMask | VK_PIPELINE_STAGE_HOST_BIT)) {
78643251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
7865315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pCB->commandBuffer), __LINE__, VALIDATION_ERROR_1e62d401, "DS",
78663251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Submitting cmdbuffer with call to VkCmdWaitEvents "
78673251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "using srcStageMask 0x%X which must be the bitwise "
78683251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "OR of the stageMask parameters used in calls to "
78693251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkCmdSetEvent and VK_PIPELINE_STAGE_HOST_BIT if "
78703251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "used with vkSetEvent but instead is 0x%X. %s",
7871315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        sourceStageMask, stageMask, validation_error_map[VALIDATION_ERROR_1e62d401]);
7872b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine    }
78733251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
7874b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine}
7875b4cc521cc1250cec2a064e22a4d840f1ab42370dMichael Lentine
787607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski// Note that we only check bits that HAVE required queueflags -- don't care entries are skipped
787707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinskistatic std::unordered_map<VkPipelineStageFlags, VkQueueFlags> supported_pipeline_stages_table = {
787807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT},
787907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT},
788007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_QUEUE_GRAPHICS_BIT},
788107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
788207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
788307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
788407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
788507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_QUEUE_GRAPHICS_BIT},
788607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, VK_QUEUE_GRAPHICS_BIT},
788707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_QUEUE_GRAPHICS_BIT},
788807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_QUEUE_GRAPHICS_BIT},
788907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_QUEUE_COMPUTE_BIT},
789007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_TRANSFER_BIT, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT},
789107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    {VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_QUEUE_GRAPHICS_BIT}};
789207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
789307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinskistatic const VkPipelineStageFlags stage_flag_bit_array[] = {VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX,
789407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,
789507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
789607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
789707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT,
789807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT,
789907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT,
790007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
790107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
790207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
790307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
790407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
790507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_TRANSFER_BIT,
790607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                            VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT};
790707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
790807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinskibool CheckStageMaskQueueCompatibility(layer_data *dev_data, VkCommandBuffer command_buffer, VkPipelineStageFlags stage_mask,
790907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                      VkQueueFlags queue_flags, const char *function, const char *src_or_dest,
791007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                      UNIQUE_VALIDATION_ERROR_CODE error_code) {
791107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    bool skip = false;
791207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    // Lookup each bit in the stagemask and check for overlap between its table bits and queue_flags
791307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    for (const auto &item : stage_flag_bit_array) {
791407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        if (stage_mask & item) {
791507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski            if ((supported_pipeline_stages_table[item] & queue_flags) == 0) {
791607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                skip |=
791707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
79189b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(command_buffer), __LINE__, error_code, "DL",
791907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            "%s(): %s flag %s is not compatible with the queue family properties of this "
792007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            "command buffer. %s",
792107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            function, src_or_dest, string_VkPipelineStageFlagBits(static_cast<VkPipelineStageFlagBits>(item)),
792207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                            validation_error_map[error_code]);
792307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski            }
792407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        }
792507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    }
792607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    return skip;
792707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski}
792807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
792907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinskibool ValidateStageMasksAgainstQueueCapabilities(layer_data *dev_data, GLOBAL_CB_NODE *cb_state,
793007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                VkPipelineStageFlags source_stage_mask, VkPipelineStageFlags dest_stage_mask,
793107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                const char *function, UNIQUE_VALIDATION_ERROR_CODE error_code) {
793207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    bool skip = false;
793307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    uint32_t queue_family_index = dev_data->commandPoolMap[cb_state->createInfo.commandPool].queueFamilyIndex;
793456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(dev_data->physical_device), instance_layer_data_map);
79359a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, dev_data->physical_device);
793607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
793707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    // Any pipeline stage included in srcStageMask or dstStageMask must be supported by the capabilities of the queue family
793807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    // specified by the queueFamilyIndex member of the VkCommandPoolCreateInfo structure that was used to create the VkCommandPool
793907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    // that commandBuffer was allocated from, as specified in the table of supported pipeline stages.
794007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
794107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    if (queue_family_index < physical_device_state->queue_family_properties.size()) {
794207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        VkQueueFlags specified_queue_flags = physical_device_state->queue_family_properties[queue_family_index].queueFlags;
794307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
794407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        if ((source_stage_mask & VK_PIPELINE_STAGE_ALL_COMMANDS_BIT) == 0) {
794507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski            skip |= CheckStageMaskQueueCompatibility(dev_data, cb_state->commandBuffer, source_stage_mask, specified_queue_flags,
794607059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                     function, "srcStageMask", error_code);
794707059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        }
794807059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        if ((dest_stage_mask & VK_PIPELINE_STAGE_ALL_COMMANDS_BIT) == 0) {
794907059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski            skip |= CheckStageMaskQueueCompatibility(dev_data, cb_state->commandBuffer, dest_stage_mask, specified_queue_flags,
795007059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski                                                     function, "dstStageMask", error_code);
795107059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski        }
795207059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    }
795307059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski    return skip;
795407059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski}
795507059341a6ab09b3bd64727d2689082828492191Mark Lobodzinski
7956d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents,
7957d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                         VkPipelineStageFlags sourceStageMask, VkPipelineStageFlags dstStageMask,
7958d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                         uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
7959d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                         uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
7960d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                         uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
7961d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    bool skip = false;
796256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
7963b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
79649a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
7965d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    if (cb_state) {
7966d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        skip |= ValidateStageMasksAgainstQueueCapabilities(dev_data, cb_state, sourceStageMask, dstStageMask, "vkCmdWaitEvents",
7967315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                           VALIDATION_ERROR_1e600918);
7968315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateStageMaskGsTsEnables(dev_data, sourceStageMask, "vkCmdWaitEvents()", VALIDATION_ERROR_1e60090e,
7969315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                             VALIDATION_ERROR_1e600912);
7970315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateStageMaskGsTsEnables(dev_data, dstStageMask, "vkCmdWaitEvents()", VALIDATION_ERROR_1e600910,
7971315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                             VALIDATION_ERROR_1e600914);
7972d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        auto first_event_index = cb_state->events.size();
79735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < eventCount; ++i) {
79749a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto event_state = GetEventNode(dev_data, pEvents[i]);
79754710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis            if (event_state) {
79769b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                addCommandBufferBinding(&event_state->cb_bindings, {HandleToUint64(pEvents[i]), kVulkanObjectTypeEvent}, cb_state);
7977d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                event_state->cb_bindings.insert(cb_state);
7978ad13b09db50a49347ea6a8c1408fcc5280042898Tobin Ehlis            }
7979d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski            cb_state->waitedEvents.insert(pEvents[i]);
7980d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski            cb_state->events.push_back(pEvents[i]);
79815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
7982d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        std::function<bool(VkQueue)> event_update =
7983d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski            std::bind(validateEventStageMask, std::placeholders::_1, cb_state, eventCount, first_event_index, sourceStageMask);
7984d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski        cb_state->eventUpdates.push_back(event_update);
7985baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdWaitEvents()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
7986315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                      VALIDATION_ERROR_1e602415);
7987ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        skip |= ValidateCmd(dev_data, cb_state, CMD_WAITEVENTS, "vkCmdWaitEvents()");
7988ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        UpdateCmdBufferLastCmd(cb_state, CMD_WAITEVENTS);
7989a90f5fa414aa0994e67cdb911938e6ae48f2ad6aMike Weiblen        skip |=
7990a90f5fa414aa0994e67cdb911938e6ae48f2ad6aMike Weiblen            ValidateBarriersToImages(dev_data, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers, "vkCmdWaitEvents()");
7991e659c986db0f3146726d6c744c75772316c3e0c6Mark Lobodzinski        if (!skip) {
7992e659c986db0f3146726d6c744c75772316c3e0c6Mark Lobodzinski            TransitionImageLayouts(dev_data, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers);
7993e659c986db0f3146726d6c744c75772316c3e0c6Mark Lobodzinski        }
7994e659c986db0f3146726d6c744c75772316c3e0c6Mark Lobodzinski
7995364a03b109f0b2b37be2e13d293fa93b8af5203aMike Weiblen        skip |= ValidateBarriers("vkCmdWaitEvents()", commandBuffer, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
7996d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                 pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
79975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
7998b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
7999d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    if (!skip)
80004a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdWaitEvents(commandBuffer, eventCount, pEvents, sourceStageMask, dstStageMask,
80014a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                               memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers,
80024a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                               imageMemoryBarrierCount, pImageMemoryBarriers);
80035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
80045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
800503122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinskistatic bool PreCallValidateCmdPipelineBarrier(layer_data *device_data, GLOBAL_CB_NODE *cb_state, VkCommandBuffer commandBuffer,
800603122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                              VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask,
800703122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                              uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
800803122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                              uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
800903122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                              uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
801003122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    bool skip = false;
801103122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    skip |= ValidateStageMasksAgainstQueueCapabilities(device_data, cb_state, srcStageMask, dstStageMask, "vkCmdPipelineBarrier",
8012315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                                       VALIDATION_ERROR_1b80093e);
8013baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt    skip |= ValidateCmdQueueFlags(device_data, cb_state, "vkCmdPipelineBarrier()",
8014315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                  VK_QUEUE_TRANSFER_BIT | VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, VALIDATION_ERROR_1b802415);
801503122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    skip |= ValidateCmd(device_data, cb_state, CMD_PIPELINEBARRIER, "vkCmdPipelineBarrier()");
8016315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= ValidateStageMaskGsTsEnables(device_data, srcStageMask, "vkCmdPipelineBarrier()", VALIDATION_ERROR_1b800920,
8017315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                         VALIDATION_ERROR_1b800924);
8018315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= ValidateStageMaskGsTsEnables(device_data, dstStageMask, "vkCmdPipelineBarrier()", VALIDATION_ERROR_1b800922,
8019315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                         VALIDATION_ERROR_1b800926);
8020a90f5fa414aa0994e67cdb911938e6ae48f2ad6aMike Weiblen    skip |= ValidateBarriersToImages(device_data, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers,
8021a90f5fa414aa0994e67cdb911938e6ae48f2ad6aMike Weiblen                                     "vkCmdPipelineBarrier()");
802203122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    skip |= ValidateBarriers("vkCmdPipelineBarrier()", commandBuffer, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
802303122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                             pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
802403122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski    return skip;
802503122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski}
802603122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski
80276f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinskistatic void PreCallRecordCmdPipelineBarrier(layer_data *device_data, GLOBAL_CB_NODE *cb_state, VkCommandBuffer commandBuffer,
80286f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski                                            uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
80296f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski    UpdateCmdBufferLastCmd(cb_state, CMD_PIPELINEBARRIER);
80306f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski    TransitionImageLayouts(device_data, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers);
80316f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski}
80326f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski
8033d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask,
8034d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                              VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags,
8035d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                              uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
8036d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                              uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
8037d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski                                              uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
8038d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    bool skip = false;
80396f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8040b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
80416f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski    GLOBAL_CB_NODE *cb_state = GetCBNode(device_data, commandBuffer);
8042d91b0b35cff4dc73d88fcf4ea567bd37997bbd98Mark Lobodzinski    if (cb_state) {
80436f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski        skip |= PreCallValidateCmdPipelineBarrier(device_data, cb_state, commandBuffer, srcStageMask, dstStageMask,
804403122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                                  memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
804503122452370ba372b7fb62eaad6ef56a963b3fb0Mark Lobodzinski                                                  pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
80466f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski        if (!skip) {
80476f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski            PreCallRecordCmdPipelineBarrier(device_data, cb_state, commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers);
80486f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski        }
80496f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski    } else {
80506f88609b0b59259ed29581f1d824ee5e9d7c82ccMark Lobodzinski        assert(0);
80515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8052b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8053a79957f762f6fc6b74c25cb94d35a3fc36967471Tony Barbour    if (!skip) {
8054a79957f762f6fc6b74c25cb94d35a3fc36967471Tony Barbour        device_data->dispatch_table.CmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, dependencyFlags, memoryBarrierCount,
8055a79957f762f6fc6b74c25cb94d35a3fc36967471Tony Barbour                                                       pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers,
8056a79957f762f6fc6b74c25cb94d35a3fc36967471Tony Barbour                                                       imageMemoryBarrierCount, pImageMemoryBarriers);
8057a79957f762f6fc6b74c25cb94d35a3fc36967471Tony Barbour    }
80585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
80595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8060d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentinebool setQueryState(VkQueue queue, VkCommandBuffer commandBuffer, QueryObject object, bool value) {
806156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
80629a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
8063d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    if (pCB) {
8064d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        pCB->queryToStateMap[object] = value;
8065d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    }
8066d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    auto queue_data = dev_data->queueMap.find(queue);
8067d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    if (queue_data != dev_data->queueMap.end()) {
8068d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        queue_data->second.queryToStateMap[object] = value;
8069d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    }
8070d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    return false;
8071d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine}
8072d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine
8073bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBeginQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot, VkFlags flags) {
80743251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
807556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8076b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
80779a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
80785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
80795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        QueryObject query = {queryPool, slot};
80805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        pCB->activeQueries.insert(query);
80815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (!pCB->startedQueries.count(query)) {
80825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pCB->startedQueries.insert(query);
80835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
80843251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdBeginQuery()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
8085315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                      VALIDATION_ERROR_17802415);
80863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_BEGINQUERY, "vkCmdBeginQuery()");
80871ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_BEGINQUERY);
80889a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        addCommandBufferBinding(&GetQueryPoolNode(dev_data, queryPool)->cb_bindings,
80899b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                {HandleToUint64(queryPool), kVulkanObjectTypeQueryPool}, pCB);
80905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8091b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
80923251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdBeginQuery(commandBuffer, queryPool, slot, flags);
80935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
80945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
809589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdEndQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot) {
8096946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
809756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8098b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
8099946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
8100946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (cb_state) {
81015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        QueryObject query = {queryPool, slot};
8102946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        if (!cb_state->activeQueries.count(query)) {
8103df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
8104315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_1ae00652, "DS",
81059b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "Ending a query before it was started: queryPool 0x%" PRIx64 ", index %d. %s",
8106315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(queryPool), slot, validation_error_map[VALIDATION_ERROR_1ae00652]);
81075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else {
8108946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            cb_state->activeQueries.erase(query);
81095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8110946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        std::function<bool(VkQueue)> query_update = std::bind(setQueryState, std::placeholders::_1, commandBuffer, query, true);
8111946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        cb_state->queryUpdates.push_back(query_update);
8112baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "VkCmdEndQuery()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
8113315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                      VALIDATION_ERROR_1ae02415);
8114946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_state, CMD_ENDQUERY, "VkCmdEndQuery()");
8115946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        UpdateCmdBufferLastCmd(cb_state, CMD_ENDQUERY);
81169a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        addCommandBufferBinding(&GetQueryPoolNode(dev_data, queryPool)->cb_bindings,
81179b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                {HandleToUint64(queryPool), kVulkanObjectTypeQueryPool}, cb_state);
81185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8119b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8120946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdEndQuery(commandBuffer, queryPool, slot);
81215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
81225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8123bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdResetQueryPool(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery,
8124bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                             uint32_t queryCount) {
8125946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
812656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8127b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
8128946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
8129946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (cb_state) {
81305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < queryCount; i++) {
81315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            QueryObject query = {queryPool, firstQuery + i};
8132946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            cb_state->waitedEventsBeforeQueryReset[query] = cb_state->waitedEvents;
8133946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            std::function<bool(VkQueue)> query_update =
8134946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                std::bind(setQueryState, std::placeholders::_1, commandBuffer, query, false);
8135946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski            cb_state->queryUpdates.push_back(query_update);
8136946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        }
8137baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "VkCmdResetQueryPool()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
8138315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                      VALIDATION_ERROR_1c602415);
8139946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_state, CMD_RESETQUERYPOOL, "VkCmdResetQueryPool()");
8140946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        UpdateCmdBufferLastCmd(cb_state, CMD_RESETQUERYPOOL);
8141315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= insideRenderPass(dev_data, cb_state, "vkCmdResetQueryPool()", VALIDATION_ERROR_1c600017);
81429a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        addCommandBufferBinding(&GetQueryPoolNode(dev_data, queryPool)->cb_bindings,
81439b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                {HandleToUint64(queryPool), kVulkanObjectTypeQueryPool}, cb_state);
81445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8145b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8146946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdResetQueryPool(commandBuffer, queryPool, firstQuery, queryCount);
81475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
81485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8149d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentinebool validateQuery(VkQueue queue, GLOBAL_CB_NODE *pCB, VkQueryPool queryPool, uint32_t queryCount, uint32_t firstQuery) {
81503251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
815156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(pCB->commandBuffer), layer_data_map);
8152d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    auto queue_data = dev_data->queueMap.find(queue);
8153cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (queue_data == dev_data->queueMap.end()) return false;
8154d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    for (uint32_t i = 0; i < queryCount; i++) {
8155d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        QueryObject query = {queryPool, firstQuery + i};
8156d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        auto query_data = queue_data->second.queryToStateMap.find(query);
8157d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        bool fail = false;
8158d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        if (query_data != queue_data->second.queryToStateMap.end()) {
8159d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            if (!query_data->second) {
8160d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                fail = true;
8161d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            }
8162d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        } else {
8163d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            auto global_query_data = dev_data->queryToStateMap.find(query);
8164d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            if (global_query_data != dev_data->queryToStateMap.end()) {
8165d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                if (!global_query_data->second) {
8166d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                    fail = true;
8167d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                }
8168d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            } else {
8169d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine                fail = true;
8170d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine            }
8171d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        }
8172d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        if (fail) {
81733251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
81749b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
81753251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Requesting a copy from query to buffer with invalid query: queryPool 0x%" PRIx64 ", index %d",
81769b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(queryPool), firstQuery + i);
8177d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine        }
8178d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine    }
81793251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
8180d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine}
8181d78749ee260a3ce7244cbfd97c11aacc2250f8d3Michael Lentine
8182bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdCopyQueryPoolResults(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery,
8183bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset,
8184bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                   VkDeviceSize stride, VkQueryResultFlags flags) {
8185946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
818656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8187b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
8188ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis
81899a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto cb_node = GetCBNode(dev_data, commandBuffer);
81909a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto dst_buff_state = GetBufferState(dev_data, dstBuffer);
81915cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis    if (cb_node && dst_buff_state) {
8192315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateMemoryIsBoundToBuffer(dev_data, dst_buff_state, "vkCmdCopyQueryPoolResults()", VALIDATION_ERROR_19400674);
8193ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Update bindings between buffer and cmd buffer
81945cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis        AddCommandBufferBindingBuffer(dev_data, cb_node, dst_buff_state);
8195ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        // Validate that DST buffer has correct usage flags set
8196315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |=
8197315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            ValidateBufferUsageFlags(dev_data, dst_buff_state, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, VALIDATION_ERROR_19400672,
8198315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                     "vkCmdCopyQueryPoolResults()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
8199e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        std::function<bool()> function = [=]() {
82005cca7b0a90e0b6fe1cc28ddbe9037c3ce3f3ee13Tobin Ehlis            SetBufferMemoryValid(dev_data, dst_buff_state, true);
8201e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves            return false;
82025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        };
82039f229695cf32913dab3fb75e5d52548ea57b3851Tobin Ehlis        cb_node->validate_functions.push_back(function);
8204946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        std::function<bool(VkQueue)> query_update =
8205ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis            std::bind(validateQuery, std::placeholders::_1, cb_node, queryPool, queryCount, firstQuery);
8206946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        cb_node->queryUpdates.push_back(query_update);
8207baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_node, "vkCmdCopyQueryPoolResults()",
8208315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                      VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, VALIDATION_ERROR_19402415);
8209946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_node, CMD_COPYQUERYPOOLRESULTS, "vkCmdCopyQueryPoolResults()");
8210ecf8b73f862ce67b99fdc57435d3d092afe4e705Mark Lobodzinski        UpdateCmdBufferLastCmd(cb_node, CMD_COPYQUERYPOOLRESULTS);
8211315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= insideRenderPass(dev_data, cb_node, "vkCmdCopyQueryPoolResults()", VALIDATION_ERROR_19400017);
82129a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        addCommandBufferBinding(&GetQueryPoolNode(dev_data, queryPool)->cb_bindings,
82139b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                {HandleToUint64(queryPool), kVulkanObjectTypeQueryPool}, cb_node);
8214ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis    } else {
8215ebc92c86f5a63df6ab4d325f83d385b23c11bf5eTobin Ehlis        assert(0);
82165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8217b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8218946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip)
82194a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdCopyQueryPoolResults(commandBuffer, queryPool, firstQuery, queryCount, dstBuffer, dstOffset,
82204a0754042cf090e131e9e769d8a3633c228625beChris Forbes                                                         stride, flags);
82215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
82225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8223bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdPushConstants(VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags,
8224bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                            uint32_t offset, uint32_t size, const void *pValues) {
8225946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
822656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8227b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
8228946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
8229946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (cb_state) {
8230baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdPushConstants()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
8231315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                      VALIDATION_ERROR_1bc02415);
8232946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_state, CMD_PUSHCONSTANTS, "vkCmdPushConstants()");
8233946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        UpdateCmdBufferLastCmd(cb_state, CMD_PUSHCONSTANTS);
82345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8235946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    skip |= validatePushConstantRange(dev_data, offset, size, "vkCmdPushConstants()");
82369e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    if (0 == stageFlags) {
8237df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
8238315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_1bc2dc03, "DS",
8239315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        "vkCmdPushConstants() call has no stageFlags set. %s", validation_error_map[VALIDATION_ERROR_1bc2dc03]);
82409e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz    }
82419e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz
8242bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz    // Check if specified push constant range falls within a pipeline-defined range which has matching stageFlags.
8243bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz    // The spec doesn't seem to disallow having multiple push constant ranges with the
8244bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz    // same offset and size, but different stageFlags.  So we can't just check the
8245bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz    // stageFlags in the first range with matching offset and size.
8246bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz    if (!skip) {
8247bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz        const auto &ranges = getPipelineLayout(dev_data, layout)->push_constant_ranges;
8248bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz        bool found_matching_range = false;
8249bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz        for (const auto &range : ranges) {
8250bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz            if ((stageFlags == range.stageFlags) && (offset >= range.offset) && (offset + size <= range.offset + range.size)) {
8251bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz                found_matching_range = true;
825215a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis                break;
8253a95cb74c9d0947ab3821b15e1289755286ea78eeKarl Schultz            }
82549e24d8153ab63bc3ac08b5a1517c203930b5de91Karl Schultz        }
8255bf0fa2ad7830118e59f0fb8ff88efae18a72e833Karl Schultz        if (!found_matching_range) {
8256315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
8257315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_1bc002de, "DS",
8258315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            "vkCmdPushConstants() stageFlags = 0x%" PRIx32
8259315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            " do not match the stageFlags in any of the ranges with"
8260315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            " offset = %d and size = %d in pipeline layout 0x%" PRIx64 ". %s",
8261315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            (uint32_t)stageFlags, offset, size, HandleToUint64(layout),
8262315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_1bc002de]);
826315a574466ede280b595c451ad52f2b7b18f20b2dTobin Ehlis        }
82645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8265b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8266946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdPushConstants(commandBuffer, layout, stageFlags, offset, size, pValues);
82675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
82685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8269bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage,
8270bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                             VkQueryPool queryPool, uint32_t slot) {
8271946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
827256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
8273b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
8274946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    GLOBAL_CB_NODE *cb_state = GetCBNode(dev_data, commandBuffer);
8275946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (cb_state) {
82765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        QueryObject query = {queryPool, slot};
8277946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        std::function<bool(VkQueue)> query_update = std::bind(setQueryState, std::placeholders::_1, commandBuffer, query, true);
8278946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        cb_state->queryUpdates.push_back(query_update);
8279baa50ccc5a8cf7a6f7474148f301802c5480e715Mike Schuchardt        skip |= ValidateCmdQueueFlags(dev_data, cb_state, "vkCmdWriteTimestamp()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
8280315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                      VALIDATION_ERROR_1e802415);
8281946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        skip |= ValidateCmd(dev_data, cb_state, CMD_WRITETIMESTAMP, "vkCmdWriteTimestamp()");
8282946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski        UpdateCmdBufferLastCmd(cb_state, CMD_WRITETIMESTAMP);
82835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8284b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
8285946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdWriteTimestamp(commandBuffer, pipelineStage, queryPool, slot);
82865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
82875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
82886600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinskistatic bool MatchUsage(layer_data *dev_data, uint32_t count, const VkAttachmentReference *attachments,
82899bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                       const VkFramebufferCreateInfo *fbci, VkImageUsageFlagBits usage_flag,
82909bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                       UNIQUE_VALIDATION_ERROR_CODE error_code) {
8291946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    bool skip = false;
82926600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
82936600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    for (uint32_t attach = 0; attach < count; attach++) {
82946600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski        if (attachments[attach].attachment != VK_ATTACHMENT_UNUSED) {
82956600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            // Attachment counts are verified elsewhere, but prevent an invalid access
82966600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            if (attachments[attach].attachment < fbci->attachmentCount) {
82976600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                const VkImageView *image_view = &fbci->pAttachments[attachments[attach].attachment];
82989a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto view_state = GetImageViewState(dev_data, *image_view);
829979fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if (view_state) {
83009a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                    const VkImageCreateInfo *ici = &GetImageState(dev_data, view_state->create_info.image)->createInfo;
83016600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                    if (ici != nullptr) {
83026600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                        if ((ici->usage & usage_flag) == 0) {
8303df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
8304df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                                            VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, error_code, "DS",
8305946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                            "vkCreateFramebuffer:  Framebuffer Attachment (%d) conflicts with the image's "
8306946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                            "IMAGE_USAGE flags (%s). %s",
8307946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                            attachments[attach].attachment, string_VkImageUsageFlagBits(usage_flag),
8308946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski                                            validation_error_map[error_code]);
83096600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                        }
83106600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                    }
83116600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski                }
83126600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            }
83136600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski        }
83146600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    }
8315946ddda6ec99e024f51a806278ba21c6779de88aMark Lobodzinski    return skip;
83166600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski}
83176600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
8318d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis// Validate VkFramebufferCreateInfo which includes:
8319d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis// 1. attachmentCount equals renderPass attachmentCount
83205ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 2. corresponding framebuffer and renderpass attachments have matching formats
83215ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 3. corresponding framebuffer and renderpass attachments have matching sample counts
83225ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 4. fb attachments only have a single mip level
83235ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 5. fb attachment dimensions are each at least as large as the fb
83245ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 6. fb attachments use idenity swizzle
83255ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis// 7. fb attachments used by renderPass for color/input/ds have correct usage bit set
83266fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis// 8. fb dimensions are within physical device limits
8327d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlisstatic bool ValidateFramebufferCreateInfo(layer_data *dev_data, const VkFramebufferCreateInfo *pCreateInfo) {
83283251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
83296600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
83309a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto rp_state = GetRenderPassState(dev_data, pCreateInfo->renderPass);
8331127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis    if (rp_state) {
8332127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis        const VkRenderPassCreateInfo *rpci = rp_state->createInfo.ptr();
8333d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis        if (rpci->attachmentCount != pCreateInfo->attachmentCount) {
83343251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(
8335d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
8336315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                HandleToUint64(pCreateInfo->renderPass), __LINE__, VALIDATION_ERROR_094006d8, "DS",
8337d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis                "vkCreateFramebuffer(): VkFramebufferCreateInfo attachmentCount of %u does not match attachmentCount of %u of "
83389bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                "renderPass (0x%" PRIxLEAST64 ") being used to create Framebuffer. %s",
83399b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                pCreateInfo->attachmentCount, rpci->attachmentCount, HandleToUint64(pCreateInfo->renderPass),
8340315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                validation_error_map[VALIDATION_ERROR_094006d8]);
83415ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis        } else {
834241ebcb6b517b1de5ae456d46d866f5e84a96a2c5Tobin Ehlis            // attachmentCounts match, so make sure corresponding attachment details line up
83435ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis            const VkImageView *image_views = pCreateInfo->pAttachments;
83445ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis            for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
83459a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto view_state = GetImageViewState(dev_data, image_views[i]);
834612d5600c2f9e32343016fd944432ba95df370797Tobin Ehlis                auto &ivci = view_state->create_info;
834779fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if (ivci.format != rpci->pAttachments[i].format) {
83483251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(
83495ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
8350315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pCreateInfo->renderPass), __LINE__, VALIDATION_ERROR_094006e0, "DS",
83519bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has format of %s that does not match "
83529bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "the format of "
83539bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "%s used by the corresponding attachment for renderPass (0x%" PRIxLEAST64 "). %s",
835479fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                        i, string_VkFormat(ivci.format), string_VkFormat(rpci->pAttachments[i].format),
8355315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pCreateInfo->renderPass), validation_error_map[VALIDATION_ERROR_094006e0]);
83565ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
83579a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                const VkImageCreateInfo *ici = &GetImageState(dev_data, ivci.image)->createInfo;
83585ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                if (ici->samples != rpci->pAttachments[i].samples) {
83593251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(
836041ebcb6b517b1de5ae456d46d866f5e84a96a2c5Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
8361315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pCreateInfo->renderPass), __LINE__, VALIDATION_ERROR_094006e2, "DS",
83629bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has %s samples that do not match "
83639bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "the %s samples used by the corresponding attachment for renderPass (0x%" PRIxLEAST64 "). %s",
836441ebcb6b517b1de5ae456d46d866f5e84a96a2c5Tobin Ehlis                        i, string_VkSampleCountFlagBits(ici->samples), string_VkSampleCountFlagBits(rpci->pAttachments[i].samples),
8365315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pCreateInfo->renderPass), validation_error_map[VALIDATION_ERROR_094006e2]);
83665ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
83675ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                // Verify that view only has a single mip level
836879fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if (ivci.subresourceRange.levelCount != 1) {
83693251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
8370315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    0, __LINE__, VALIDATION_ERROR_094006e6, "DS",
83713251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has mip levelCount of %u "
83723251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "but only a single mip level (levelCount ==  1) is allowed when creating a Framebuffer. %s",
8373315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    i, ivci.subresourceRange.levelCount, validation_error_map[VALIDATION_ERROR_094006e6]);
83745ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
837579fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                const uint32_t mip_level = ivci.subresourceRange.baseMipLevel;
8376aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                uint32_t mip_width = max(1u, ici->extent.width >> mip_level);
8377aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                uint32_t mip_height = max(1u, ici->extent.height >> mip_level);
837879fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if ((ivci.subresourceRange.layerCount < pCreateInfo->layers) || (mip_width < pCreateInfo->width) ||
8379aac6fea2aeb81a0d354d80a9226bdc5de2aef5e2Tobin Ehlis                    (mip_height < pCreateInfo->height)) {
83802c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                    skip |= log_msg(
83812c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
8382315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        VALIDATION_ERROR_094006e4, "DS",
83832c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                        "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u mip level %u has dimensions smaller "
83842c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                        "than the corresponding framebuffer dimensions. Here are the respective dimensions for attachment #%u, "
83852c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                        "framebuffer:\n"
83862c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                        "width: %u, %u\n"
83872c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                        "height: %u, %u\n"
83882c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                        "layerCount: %u, %u\n%s",
83892c911c34092d685a7fa4630028f6fcf4bf80e349Cort Stratton                        i, ivci.subresourceRange.baseMipLevel, i, mip_width, pCreateInfo->width, mip_height, pCreateInfo->height,
8390315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        ivci.subresourceRange.layerCount, pCreateInfo->layers, validation_error_map[VALIDATION_ERROR_094006e4]);
83915ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
839279fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                if (((ivci.components.r != VK_COMPONENT_SWIZZLE_IDENTITY) && (ivci.components.r != VK_COMPONENT_SWIZZLE_R)) ||
839379fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                    ((ivci.components.g != VK_COMPONENT_SWIZZLE_IDENTITY) && (ivci.components.g != VK_COMPONENT_SWIZZLE_G)) ||
839479fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                    ((ivci.components.b != VK_COMPONENT_SWIZZLE_IDENTITY) && (ivci.components.b != VK_COMPONENT_SWIZZLE_B)) ||
839579fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                    ((ivci.components.a != VK_COMPONENT_SWIZZLE_IDENTITY) && (ivci.components.a != VK_COMPONENT_SWIZZLE_A))) {
83963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(
83975b9ab1fb8720c30edfbe8dd974e2364425471ad5Mark Lobodzinski                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
8398315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        VALIDATION_ERROR_094006e8, "DS",
8399da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has non-identy swizzle. All framebuffer "
8400da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "attachments must have been created with the identity swizzle. Here are the actual swizzle values:\n"
8401da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "r swizzle = %s\n"
8402da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "g swizzle = %s\n"
8403da5b8b1df2368168be93e563eccdb500d62b97a5Tobin Ehlis                        "b swizzle = %s\n"
84049bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "a swizzle = %s\n"
84059bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        "%s",
840679fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis                        i, string_VkComponentSwizzle(ivci.components.r), string_VkComponentSwizzle(ivci.components.g),
84079bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                        string_VkComponentSwizzle(ivci.components.b), string_VkComponentSwizzle(ivci.components.a),
8408315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_094006e8]);
84095ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis                }
84105ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis            }
8411d73d9c5ffd42f300d3ec49f64910a2b370694186Tobin Ehlis        }
84125ef4ed03801d1456b7c30dd59ea014be126df771Tobin Ehlis        // Verify correct attachment usage flags
84136600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski        for (uint32_t subpass = 0; subpass < rpci->subpassCount; subpass++) {
84146600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            // Verify input attachments:
84153251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |=
84169bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                MatchUsage(dev_data, rpci->pSubpasses[subpass].inputAttachmentCount, rpci->pSubpasses[subpass].pInputAttachments,
8417315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                           pCreateInfo, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, VALIDATION_ERROR_094006de);
84186600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            // Verify color attachments:
84193251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |=
84209bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                MatchUsage(dev_data, rpci->pSubpasses[subpass].colorAttachmentCount, rpci->pSubpasses[subpass].pColorAttachments,
8421315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                           pCreateInfo, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VALIDATION_ERROR_094006da);
84226600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            // Verify depth/stencil attachments:
84236600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            if (rpci->pSubpasses[subpass].pDepthStencilAttachment != nullptr) {
84243251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= MatchUsage(dev_data, 1, rpci->pSubpasses[subpass].pDepthStencilAttachment, pCreateInfo,
8425315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                   VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VALIDATION_ERROR_094006dc);
84266600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski            }
84276600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski        }
84286600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski    }
84296fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis    // Verify FB dimensions are within physical device limits
84309bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    if (pCreateInfo->width > dev_data->phys_dev_properties.properties.limits.maxFramebufferWidth) {
84313251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
8432315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        VALIDATION_ERROR_094006ec, "DS",
84333251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo width exceeds physical device limits. "
84343251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Requested width: %u, device max: %u\n"
84353251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "%s",
84363251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        pCreateInfo->width, dev_data->phys_dev_properties.properties.limits.maxFramebufferWidth,
8437315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_094006ec]);
84389bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    }
84399bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    if (pCreateInfo->height > dev_data->phys_dev_properties.properties.limits.maxFramebufferHeight) {
84403251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
8441315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        VALIDATION_ERROR_094006f0, "DS",
84423251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo height exceeds physical device limits. "
84433251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Requested height: %u, device max: %u\n"
84443251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "%s",
84453251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        pCreateInfo->height, dev_data->phys_dev_properties.properties.limits.maxFramebufferHeight,
8446315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_094006f0]);
84479bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    }
84489bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt    if (pCreateInfo->layers > dev_data->phys_dev_properties.properties.limits.maxFramebufferLayers) {
84493251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
8450315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        VALIDATION_ERROR_094006f4, "DS",
84513251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo layers exceeds physical device limits. "
84523251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "Requested layers: %u, device max: %u\n"
84533251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "%s",
84543251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        pCreateInfo->layers, dev_data->phys_dev_properties.properties.limits.maxFramebufferLayers,
8455315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_094006f4]);
84566fb721e0f21c85d4457561d17c196280601cebc1Tobin Ehlis    }
8457c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton    // Verify FB dimensions are greater than zero
8458c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton    if (pCreateInfo->width <= 0) {
8459c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
8460315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        VALIDATION_ERROR_094006ea, "DS",
8461c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton                        "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo width must be greater than zero. %s",
8462315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_094006ea]);
8463c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton    }
8464c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton    if (pCreateInfo->height <= 0) {
8465c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
8466315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        VALIDATION_ERROR_094006ee, "DS",
8467c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton                        "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo height must be greater than zero. %s",
8468315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_094006ee]);
8469c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton    }
8470c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton    if (pCreateInfo->layers <= 0) {
8471c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
8472315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        VALIDATION_ERROR_094006f2, "DS",
8473c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton                        "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo layers must be greater than zero. %s",
8474315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_094006f2]);
8475c70c914e514d6ee222af18505e6d4ce8387c3fa2Cort Stratton    }
84763251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
84776600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski}
84786600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
847964c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis// Validate VkFramebufferCreateInfo state prior to calling down chain to create Framebuffer object
848064c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis//  Return true if an error is encountered and callback returns true to skip call down chain
848164c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis//   false indicates that call down chain should proceed
848264c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlisstatic bool PreCallValidateCreateFramebuffer(layer_data *dev_data, const VkFramebufferCreateInfo *pCreateInfo) {
848364c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    // TODO : Verify that renderPass FB is created with is compatible with FB
84843251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
84853251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= ValidateFramebufferCreateInfo(dev_data, pCreateInfo);
84863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
848764c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis}
848864c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis
848954e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis// CreateFramebuffer state has been validated and call down chain completed so record new framebuffer object
849054e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlisstatic void PostCallRecordCreateFramebuffer(layer_data *dev_data, const VkFramebufferCreateInfo *pCreateInfo, VkFramebuffer fb) {
849154e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis    // Shadow create info and store in map
8492c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    std::unique_ptr<FRAMEBUFFER_STATE> fb_state(
8493c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis        new FRAMEBUFFER_STATE(fb, pCreateInfo, dev_data->renderPassMap[pCreateInfo->renderPass]->createInfo.ptr()));
849476f04ca0e692f9f15d5ef7e0c658c24d11f34ebcTobin Ehlis
849554e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
849654e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        VkImageView view = pCreateInfo->pAttachments[i];
84979a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto view_state = GetImageViewState(dev_data, view);
849879fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis        if (!view_state) {
849954e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis            continue;
850054e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        }
850154e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        MT_FB_ATTACHMENT_INFO fb_info;
8502883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis        fb_info.view_state = view_state;
850379fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis        fb_info.image = view_state->create_info.image;
8504c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis        fb_state->attachments.push_back(fb_info);
850554e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis    }
8506c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    dev_data->frameBufferMap[fb] = std::move(fb_state);
850754e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis}
850854e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis
850989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateFramebuffer(VkDevice device, const VkFramebufferCreateInfo *pCreateInfo,
8510bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 const VkAllocationCallbacks *pAllocator, VkFramebuffer *pFramebuffer) {
851156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
851264c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    std::unique_lock<std::mutex> lock(global_lock);
85133251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = PreCallValidateCreateFramebuffer(dev_data, pCreateInfo);
851464c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis    lock.unlock();
851564c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis
85163251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
851764c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis
85184a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateFramebuffer(device, pCreateInfo, pAllocator, pFramebuffer);
85196600a7662f6dac6a8c8622a8305f02625439bf30Mark Lobodzinski
85205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
852164c259c2660d24b5b032f0cfa668de086dcd7eb4Tobin Ehlis        lock.lock();
852254e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        PostCallRecordCreateFramebuffer(dev_data, pCreateInfo, *pFramebuffer);
852354e0bb0ace13cc34255e0dc9ca6b0da2b4ac5be1Tobin Ehlis        lock.unlock();
85245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
85255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
85265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
85275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
85284e11bb1277f55311686a42000520791e1db1dd7bbungemanstatic bool FindDependency(const uint32_t index, const uint32_t dependent, const std::vector<DAGNode> &subpass_to_node,
8529e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                           std::unordered_set<uint32_t> &processed_nodes) {
85305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If we have already checked this node we have not found a dependency path so return false.
8531cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (processed_nodes.count(index)) return false;
85325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    processed_nodes.insert(index);
85335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    const DAGNode &node = subpass_to_node[index];
85345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Look for a dependency path. If one exists return true else recurse on the previous nodes.
85354e11bb1277f55311686a42000520791e1db1dd7bbungeman    if (std::find(node.prev.begin(), node.prev.end(), dependent) == node.prev.end()) {
85365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto elem : node.prev) {
8537cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (FindDependency(elem, dependent, subpass_to_node, processed_nodes)) return true;
85385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
85395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    } else {
8540e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        return true;
85415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8542e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    return false;
85435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
85445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
85454e11bb1277f55311686a42000520791e1db1dd7bbungemanstatic bool CheckDependencyExists(const layer_data *dev_data, const uint32_t subpass,
85463251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                  const std::vector<uint32_t> &dependent_subpasses, const std::vector<DAGNode> &subpass_to_node,
85473251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                  bool &skip) {
8548e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool result = true;
85495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Loop through all subpasses that share the same attachment and make sure a dependency exists
85505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t k = 0; k < dependent_subpasses.size(); ++k) {
8551cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (static_cast<uint32_t>(subpass) == dependent_subpasses[k]) continue;
85525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const DAGNode &node = subpass_to_node[subpass];
85535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Check for a specified dependency between the two nodes. If one exists we are done.
85545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto prev_elem = std::find(node.prev.begin(), node.prev.end(), dependent_subpasses[k]);
85555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto next_elem = std::find(node.next.begin(), node.next.end(), dependent_subpasses[k]);
85565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (prev_elem == node.prev.end() && next_elem == node.next.end()) {
85577655cb8b5eb52badee0b011729a05afa36316d69Jan-Harald Fredriksen            // If no dependency exits an implicit dependency still might. If not, throw an error.
85585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            std::unordered_set<uint32_t> processed_nodes;
85597655cb8b5eb52badee0b011729a05afa36316d69Jan-Harald Fredriksen            if (!(FindDependency(subpass, dependent_subpasses[k], subpass_to_node, processed_nodes) ||
8560bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                  FindDependency(dependent_subpasses[k], subpass, subpass_to_node, processed_nodes))) {
85613251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
85623251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
85633251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "A dependency between subpasses %d and %d must exist but one is not specified.", subpass,
85643251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                dependent_subpasses[k]);
8565e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                result = false;
85665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
85675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
85685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
85695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
85705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
85715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
85728860b85a52096f9f9b28616bc37feed505497a54Chris Forbesstatic bool CheckPreserved(const layer_data *dev_data, const VkRenderPassCreateInfo *pCreateInfo, const int index,
85733251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                           const uint32_t attachment, const std::vector<DAGNode> &subpass_to_node, int depth, bool &skip) {
85745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    const DAGNode &node = subpass_to_node[index];
85755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If this node writes to the attachment return true as next nodes need to preserve the attachment.
85765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[index];
85775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
8578cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (attachment == subpass.pColorAttachments[j].attachment) return true;
85795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8580a4ea781e8fff70c9db0bedad7fcb6bba08e35da7Tony Barbour    for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
8581a4ea781e8fff70c9db0bedad7fcb6bba08e35da7Tony Barbour        if (attachment == subpass.pInputAttachments[j].attachment) return true;
8582a4ea781e8fff70c9db0bedad7fcb6bba08e35da7Tony Barbour    }
85835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
8584cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (attachment == subpass.pDepthStencilAttachment->attachment) return true;
85855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
8586e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves    bool result = false;
85875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Loop through previous nodes and see if any of them write to the attachment.
85885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto elem : node.prev) {
85893251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        result |= CheckPreserved(dev_data, pCreateInfo, elem, attachment, subpass_to_node, depth + 1, skip);
85905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
85915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If the attachment was written to by a previous node than this node needs to preserve it.
85925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result && depth > 0) {
8593e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        bool has_preserved = false;
85945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.preserveAttachmentCount; ++j) {
85955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (subpass.pPreserveAttachments[j] == attachment) {
8596e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                has_preserved = true;
85975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                break;
85985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
85995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
8600e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves        if (!has_preserved) {
86013251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
86023251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
86033251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Attachment %d is used by a later subpass and must be preserved in subpass %d.", attachment, index);
86045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
86055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
86065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
86075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
86085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8609cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskitemplate <class T>
8610cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskibool isRangeOverlapping(T offset1, T size1, T offset2, T size2) {
86115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return (((offset1 + size1) > offset2) && ((offset1 + size1) < (offset2 + size2))) ||
86125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis           ((offset1 > offset2) && (offset1 < (offset2 + size2)));
86135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
86145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
86155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlisbool isRegionOverlapping(VkImageSubresourceRange range1, VkImageSubresourceRange range2) {
86165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return (isRangeOverlapping(range1.baseMipLevel, range1.levelCount, range2.baseMipLevel, range2.levelCount) &&
86175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            isRangeOverlapping(range1.baseArrayLayer, range1.layerCount, range2.baseArrayLayer, range2.layerCount));
86185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
86195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
8620c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlisstatic bool ValidateDependencies(const layer_data *dev_data, FRAMEBUFFER_STATE const *framebuffer,
8621127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                                 RENDER_PASS_STATE const *renderPass) {
86223251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
8623fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    auto const pFramebufferInfo = framebuffer->createInfo.ptr();
8624fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes    auto const pCreateInfo = renderPass->createInfo.ptr();
8625bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto const &subpass_to_node = renderPass->subpassToNode;
86265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<std::vector<uint32_t>> output_attachment_to_subpass(pCreateInfo->attachmentCount);
86275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<std::vector<uint32_t>> input_attachment_to_subpass(pCreateInfo->attachmentCount);
86285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    std::vector<std::vector<uint32_t>> overlapping_attachments(pCreateInfo->attachmentCount);
86295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Find overlapping attachments
86305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
86315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = i + 1; j < pCreateInfo->attachmentCount; ++j) {
86325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            VkImageView viewi = pFramebufferInfo->pAttachments[i];
86335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            VkImageView viewj = pFramebufferInfo->pAttachments[j];
86345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (viewi == viewj) {
86355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[i].push_back(j);
86365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[j].push_back(i);
86375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                continue;
86385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
86399a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto view_state_i = GetImageViewState(dev_data, viewi);
86409a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto view_state_j = GetImageViewState(dev_data, viewj);
864179fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis            if (!view_state_i || !view_state_j) {
86425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                continue;
86435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
864479fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis            auto view_ci_i = view_state_i->create_info;
864579fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis            auto view_ci_j = view_state_j->create_info;
864679fde938178535f598e030a0e9d19a0cb61b72e0Tobin Ehlis            if (view_ci_i.image == view_ci_j.image && isRegionOverlapping(view_ci_i.subresourceRange, view_ci_j.subresourceRange)) {
86475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[i].push_back(j);
86485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[j].push_back(i);
86495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                continue;
86505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
86519a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto image_data_i = GetImageState(dev_data, view_ci_i.image);
86529a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto image_data_j = GetImageState(dev_data, view_ci_j.image);
86536d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            if (!image_data_i || !image_data_j) {
86545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                continue;
86555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
8656e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis            if (image_data_i->binding.mem == image_data_j->binding.mem &&
8657e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis                isRangeOverlapping(image_data_i->binding.offset, image_data_i->binding.size, image_data_j->binding.offset,
8658e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis                                   image_data_j->binding.size)) {
86595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[i].push_back(j);
86605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                overlapping_attachments[j].push_back(i);
86615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
86625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
86635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
86645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < overlapping_attachments.size(); ++i) {
86655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t attachment = i;
86665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (auto other_attachment : overlapping_attachments[i]) {
86675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!(pCreateInfo->pAttachments[attachment].flags & VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT)) {
86689b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT,
8669315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                HandleToUint64(framebuffer->framebuffer), __LINE__, VALIDATION_ERROR_12200682, "DS",
86709b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "Attachment %d aliases attachment %d but doesn't "
86719b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "set VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT. %s",
8672315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                attachment, other_attachment, validation_error_map[VALIDATION_ERROR_12200682]);
86735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
86745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!(pCreateInfo->pAttachments[other_attachment].flags & VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT)) {
86759b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT,
8676315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                HandleToUint64(framebuffer->framebuffer), __LINE__, VALIDATION_ERROR_12200682, "DS",
86779b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "Attachment %d aliases attachment %d but doesn't "
86789b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "set VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT. %s",
8679315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                other_attachment, attachment, validation_error_map[VALIDATION_ERROR_12200682]);
86805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
86815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
86825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
86835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Find for each attachment the subpasses that use them.
86841c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young    unordered_set<uint32_t> attachmentIndices;
86855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
86865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
86871c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young        attachmentIndices.clear();
86885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
86895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t attachment = subpass.pInputAttachments[j].attachment;
8690cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) continue;
86915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            input_attachment_to_subpass[attachment].push_back(i);
86925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            for (auto overlapping_attachment : overlapping_attachments[attachment]) {
86935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                input_attachment_to_subpass[overlapping_attachment].push_back(i);
86945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
86955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
86965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
86975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t attachment = subpass.pColorAttachments[j].attachment;
8698cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) continue;
86995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            output_attachment_to_subpass[attachment].push_back(i);
87005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            for (auto overlapping_attachment : overlapping_attachments[attachment]) {
87015b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                output_attachment_to_subpass[overlapping_attachment].push_back(i);
87025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
87031c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young            attachmentIndices.insert(attachment);
87045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
87055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
87065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            uint32_t attachment = subpass.pDepthStencilAttachment->attachment;
87075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            output_attachment_to_subpass[attachment].push_back(i);
87085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            for (auto overlapping_attachment : overlapping_attachments[attachment]) {
87095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                output_attachment_to_subpass[overlapping_attachment].push_back(i);
87105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
87111c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young
87121c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young            if (attachmentIndices.count(attachment)) {
87133251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
8714df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
8715df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
87168860b85a52096f9f9b28616bc37feed505497a54Chris Forbes                            "Cannot use same attachment (%u) as both color and depth output in same subpass (%u).", attachment, i);
87171c1ee7bf64fb8cc2ba4b8661baa11dce24b3b23aMark Young            }
87185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
87195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
87205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // If there is a dependency needed make sure one exists
87215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
87225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
87235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // If the attachment is an input then all subpasses that output must have a dependency relationship
87245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
872593fe72ec8460857bdb3c101095e6eb96d6171341Chris Forbes            uint32_t attachment = subpass.pInputAttachments[j].attachment;
8726cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) continue;
87273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            CheckDependencyExists(dev_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip);
87285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
87295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // If the attachment is an output then all subpasses that use the attachment must have a dependency relationship
87305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
873193fe72ec8460857bdb3c101095e6eb96d6171341Chris Forbes            uint32_t attachment = subpass.pColorAttachments[j].attachment;
8732cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) continue;
87333251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            CheckDependencyExists(dev_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip);
87343251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            CheckDependencyExists(dev_data, i, input_attachment_to_subpass[attachment], subpass_to_node, skip);
87355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
87365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
87375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            const uint32_t &attachment = subpass.pDepthStencilAttachment->attachment;
87383251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            CheckDependencyExists(dev_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip);
87393251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            CheckDependencyExists(dev_data, i, input_attachment_to_subpass[attachment], subpass_to_node, skip);
87405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
87415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
87425b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // Loop through implicit dependencies, if this pass reads make sure the attachment is preserved for all passes after it was
87435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    // written.
87445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
87455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
87465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
87473251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            CheckPreserved(dev_data, pCreateInfo, i, subpass.pInputAttachments[j].attachment, subpass_to_node, 0, skip);
87485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
87495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
87503251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
87515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
87525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
875332f68580aa01aab3e923cb52915a1d3dd4e993c5Chris Forbesstatic bool CreatePassDAG(const layer_data *dev_data, const VkRenderPassCreateInfo *pCreateInfo,
8754e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                          std::vector<DAGNode> &subpass_to_node, std::vector<bool> &has_self_dependency) {
87553251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
87565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
87575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        DAGNode &subpass_node = subpass_to_node[i];
87585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        subpass_node.pass = i;
87595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
87605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->dependencyCount; ++i) {
87615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        const VkSubpassDependency &dependency = pCreateInfo->pDependencies[i];
876266a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes        if (dependency.srcSubpass == VK_SUBPASS_EXTERNAL || dependency.dstSubpass == VK_SUBPASS_EXTERNAL) {
876366a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes            if (dependency.srcSubpass == dependency.dstSubpass) {
87643251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
8765df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
8766df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS", "The src and dest subpasses cannot both be external.");
876766a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes            }
876866a7318a24c9dd8162a6ae49fd62867a263d4402Chris Forbes        } else if (dependency.srcSubpass > dependency.dstSubpass) {
87693251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
87703251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
87713251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Depedency graph must be specified such that an earlier pass cannot depend on a later pass.");
87725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        } else if (dependency.srcSubpass == dependency.dstSubpass) {
87735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            has_self_dependency[dependency.srcSubpass] = true;
87745c6aacf95832467d52b2fde1130b04bef559573aChris Forbes        } else {
87755c6aacf95832467d52b2fde1130b04bef559573aChris Forbes            subpass_to_node[dependency.dstSubpass].prev.push_back(dependency.srcSubpass);
87765c6aacf95832467d52b2fde1130b04bef559573aChris Forbes            subpass_to_node[dependency.srcSubpass].next.push_back(dependency.dstSubpass);
87775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
87785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
87793251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
87805b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
8781918c283ac4f8c604b79abd0c8b5706d2a7352a34Chris Forbes
878289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo,
8783bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                  const VkAllocationCallbacks *pAllocator, VkShaderModule *pShaderModule) {
878456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
87853251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
8786c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski    spv_result_t spv_valid = SPV_SUCCESS;
8787b1f65702539fd041337fccd493dc6d38dd2a603eChris Forbes
8788e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski    if (!GetDisables(dev_data)->shader_validation) {
8789a149f1a0cb39b48b19822c8cf9ef2426cd2251dfMark Lobodzinski        if (!dev_data->extensions.vk_nv_glsl_shader && (pCreateInfo->codeSize % 4)) {
87900fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
8791315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            __LINE__, VALIDATION_ERROR_12a00ac0, "SC",
87920fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski                            "SPIR-V module not valid: Codesize must be a multiple of 4 but is " PRINTF_SIZE_T_SPECIFIER ". %s",
8793315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            pCreateInfo->codeSize, validation_error_map[VALIDATION_ERROR_12a00ac0]);
87940fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski        } else {
87950fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski            // Use SPIRV-Tools validator to try and catch any issues with the module itself
87960fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski            spv_context ctx = spvContextCreate(SPV_ENV_VULKAN_1_0);
87970fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski            spv_const_binary_t binary{ pCreateInfo->pCode, pCreateInfo->codeSize / sizeof(uint32_t) };
87980fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski            spv_diagnostic diag = nullptr;
87990fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski
88000fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski            spv_valid = spvValidate(ctx, &binary, &diag);
88010fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski            if (spv_valid != SPV_SUCCESS) {
8802a149f1a0cb39b48b19822c8cf9ef2426cd2251dfMark Lobodzinski                if (!dev_data->extensions.vk_nv_glsl_shader || (pCreateInfo->pCode[0] == spv::MagicNumber)) {
88030fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski                    skip |= log_msg(dev_data->report_data,
88040fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski                        spv_valid == SPV_WARNING ? VK_DEBUG_REPORT_WARNING_BIT_EXT : VK_DEBUG_REPORT_ERROR_BIT_EXT,
88050fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski                        VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, SHADER_CHECKER_INCONSISTENT_SPIRV, "SC",
88060fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski                        "SPIR-V module not valid: %s", diag && diag->error ? diag->error : "(no error text)");
88070fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski                }
8808c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski            }
88095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
88100fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski            spvDiagnosticDestroy(diag);
88110fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski            spvContextDestroy(ctx);
88120fbb73dbb674f7655607f91b675a1b8bb9151bd2Mark Lobodzinski        }
8813b1f65702539fd041337fccd493dc6d38dd2a603eChris Forbes
88143251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
8815e3443707b0f51ba7c6c458c5039dd3004c38b73eMark Lobodzinski    }
88165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
88174a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult res = dev_data->dispatch_table.CreateShaderModule(device, pCreateInfo, pAllocator, pShaderModule);
88185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
881959ae0ccadec962d9ca2cce7584fad6c57c1a4458Tobin Ehlis    if (res == VK_SUCCESS) {
8820b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
8821c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski        const auto new_shader_module = (SPV_SUCCESS == spv_valid ? new shader_module(pCreateInfo) : new shader_module());
8822c73589f3e7b40b57b769dd1e3e9b03e4231b4c69Mark Lobodzinski        dev_data->shaderModuleMap[*pShaderModule] = unique_ptr<shader_module>(new_shader_module);
88235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
88245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return res;
88255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
88265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
88274f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinskistatic bool ValidateAttachmentIndex(layer_data *dev_data, uint32_t attachment, uint32_t attachment_count, const char *type) {
88283251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
88294f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    if (attachment >= attachment_count && attachment != VK_ATTACHMENT_UNUSED) {
88303251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
8831315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        VALIDATION_ERROR_12200684, "DS",
88323251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "CreateRenderPass: %s attachment %d must be less than the total number of attachments %d. %s", type,
8833315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        attachment, attachment_count, validation_error_map[VALIDATION_ERROR_12200684]);
88344f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    }
88353251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
88364f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski}
88374f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
8838bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic bool IsPowerOfTwo(unsigned x) { return x && !(x & (x - 1)); }
8839805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
88404f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinskistatic bool ValidateRenderpassAttachmentUsage(layer_data *dev_data, const VkRenderPassCreateInfo *pCreateInfo) {
88413251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
88424f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
88434f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
88444f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        if (subpass.pipelineBindPoint != VK_PIPELINE_BIND_POINT_GRAPHICS) {
88453251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
8846315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            __LINE__, VALIDATION_ERROR_14000698, "DS",
88473251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "CreateRenderPass: Pipeline bind point for subpass %d must be VK_PIPELINE_BIND_POINT_GRAPHICS. %s", i,
8848315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_14000698]);
88494f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
8850ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton
88514f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        for (uint32_t j = 0; j < subpass.preserveAttachmentCount; ++j) {
88524f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            uint32_t attachment = subpass.pPreserveAttachments[j];
88534f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            if (attachment == VK_ATTACHMENT_UNUSED) {
88543251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
8855315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                __LINE__, VALIDATION_ERROR_140006aa, "DS",
88563251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "CreateRenderPass:  Preserve attachment (%d) must not be VK_ATTACHMENT_UNUSED. %s", j,
8857315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                validation_error_map[VALIDATION_ERROR_140006aa]);
88584f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            } else {
88593251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Preserve");
8860ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton
8861ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                bool found = (subpass.pDepthStencilAttachment != NULL && subpass.pDepthStencilAttachment->attachment == attachment);
8862ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                for (uint32_t r = 0; !found && r < subpass.inputAttachmentCount; ++r) {
8863ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                    found = (subpass.pInputAttachments[r].attachment == attachment);
8864ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                }
8865ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                for (uint32_t r = 0; !found && r < subpass.colorAttachmentCount; ++r) {
8866ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                    found = (subpass.pColorAttachments[r].attachment == attachment) ||
8867ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                            (subpass.pResolveAttachments != NULL && subpass.pResolveAttachments[r].attachment == attachment);
8868ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                }
8869ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                if (found) {
8870ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                    skip |= log_msg(
8871ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
8872315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        VALIDATION_ERROR_140006ac, "DS",
8873ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                        "CreateRenderPass: subpass %u pPreserveAttachments[%u] (%u) must not be used elsewhere in the subpass. %s",
8874315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        i, j, attachment, validation_error_map[VALIDATION_ERROR_140006ac]);
8875ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                }
88764f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            }
88774f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
88786a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes
8879bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto subpass_performs_resolve =
8880bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            subpass.pResolveAttachments &&
8881bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            std::any_of(subpass.pResolveAttachments, subpass.pResolveAttachments + subpass.colorAttachmentCount,
8882bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        [](VkAttachmentReference ref) { return ref.attachment != VK_ATTACHMENT_UNUSED; });
88836a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes
8884805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes        unsigned sample_count = 0;
8885805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
88864f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
88874f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            uint32_t attachment;
88884f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            if (subpass.pResolveAttachments) {
88894f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                attachment = subpass.pResolveAttachments[j].attachment;
88903251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Resolve");
88916a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes
88923251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                if (!skip && attachment != VK_ATTACHMENT_UNUSED &&
88936a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes                    pCreateInfo->pAttachments[attachment].samples != VK_SAMPLE_COUNT_1_BIT) {
88943251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
8895315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    0, __LINE__, VALIDATION_ERROR_140006a2, "DS",
88963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "CreateRenderPass:  Subpass %u requests multisample resolve into attachment %u, "
88973251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "which must have VK_SAMPLE_COUNT_1_BIT but has %s. %s",
88983251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    i, attachment, string_VkSampleCountFlagBits(pCreateInfo->pAttachments[attachment].samples),
8899315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    validation_error_map[VALIDATION_ERROR_140006a2]);
89006a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes                }
8901ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton
8902ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                if (!skip && subpass.pResolveAttachments[j].attachment != VK_ATTACHMENT_UNUSED &&
8903ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                    subpass.pColorAttachments[j].attachment == VK_ATTACHMENT_UNUSED) {
8904ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
8905315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    0, __LINE__, VALIDATION_ERROR_1400069e, "DS",
8906ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                                    "CreateRenderPass:  Subpass %u requests multisample resolve from attachment %u "
8907ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                                    "which has attachment=VK_ATTACHMENT_UNUSED. %s",
8908315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    i, attachment, validation_error_map[VALIDATION_ERROR_1400069e]);
8909ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                }
89104f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            }
89114f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            attachment = subpass.pColorAttachments[j].attachment;
89123251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Color");
89136a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes
89143251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            if (!skip && attachment != VK_ATTACHMENT_UNUSED) {
8915805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes                sample_count |= (unsigned)pCreateInfo->pAttachments[attachment].samples;
8916805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
8917bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (subpass_performs_resolve && pCreateInfo->pAttachments[attachment].samples == VK_SAMPLE_COUNT_1_BIT) {
89183251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
8919315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    0, __LINE__, VALIDATION_ERROR_140006a0, "DS",
89203251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "CreateRenderPass:  Subpass %u requests multisample resolve from attachment %u "
89213251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "which has VK_SAMPLE_COUNT_1_BIT. %s",
8922315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    i, attachment, validation_error_map[VALIDATION_ERROR_140006a0]);
8923dc7c45f01ae5690f7c969b4760463c1a6bac52d5Chris Forbes                }
8924ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton
8925ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                if (subpass_performs_resolve && subpass.pResolveAttachments[j].attachment != VK_ATTACHMENT_UNUSED) {
8926ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                    const auto &color_desc = pCreateInfo->pAttachments[attachment];
8927ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                    const auto &resolve_desc = pCreateInfo->pAttachments[subpass.pResolveAttachments[j].attachment];
8928ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                    if (color_desc.format != resolve_desc.format) {
8929315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        skip |=
8930315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
8931315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    0, __LINE__, VALIDATION_ERROR_140006a4, "DS",
8932315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    "CreateRenderPass:  Subpass %u pColorAttachments[%u] resolves to an attachment with a "
8933315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    "different format. "
8934315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    "color format: %u, resolve format: %u. %s",
8935315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    i, j, color_desc.format, resolve_desc.format, validation_error_map[VALIDATION_ERROR_140006a4]);
8936ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                    }
8937ce7bf009f8fc7e268efdc76ba61e3491d290ebd9Cort Stratton                }
89386a3bc5f071fe21799f0f7ae844716c333f11f39cChris Forbes            }
89394f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
8940dc7c45f01ae5690f7c969b4760463c1a6bac52d5Chris Forbes
89414f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
89424f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            uint32_t attachment = subpass.pDepthStencilAttachment->attachment;
89433251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Depth stencil");
8944805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
89453251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            if (!skip && attachment != VK_ATTACHMENT_UNUSED) {
8946805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes                sample_count |= (unsigned)pCreateInfo->pAttachments[attachment].samples;
8947805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes            }
89484f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
8949dc7c45f01ae5690f7c969b4760463c1a6bac52d5Chris Forbes
89504f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
89514f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski            uint32_t attachment = subpass.pInputAttachments[j].attachment;
89523251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= ValidateAttachmentIndex(dev_data, attachment, pCreateInfo->attachmentCount, "Input");
89534f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        }
8954805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes
8955805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes        if (sample_count && !IsPowerOfTwo(sample_count)) {
89563251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
8957315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            __LINE__, VALIDATION_ERROR_0082b401, "DS",
89583251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "CreateRenderPass:  Subpass %u attempts to render to "
89593251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "attachments with inconsistent sample counts. %s",
8960315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            i, validation_error_map[VALIDATION_ERROR_0082b401]);
8961805ec497391f6bc513f7653ba6d535c509b54062Chris Forbes        }
89624f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    }
89633251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
89644f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski}
89654f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
89665245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbesstatic void MarkAttachmentFirstUse(RENDER_PASS_STATE *render_pass,
89675245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                                   uint32_t index,
89685245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                                   bool is_read) {
89695245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes    if (index == VK_ATTACHMENT_UNUSED)
89705245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes        return;
89715245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes
89725245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes    if (!render_pass->attachment_first_read.count(index))
89735245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes        render_pass->attachment_first_read[index] = is_read;
89745245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes}
89755245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes
897689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
89774f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski                                                const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) {
89783251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
897956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
89804f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
89814f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    std::unique_lock<std::mutex> lock(global_lock);
89824f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    // TODO: As part of wrapping up the mem_tracker/core_validation merge the following routine should be consolidated with
89834f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    //       ValidateLayouts.
89843251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= ValidateRenderpassAttachmentUsage(dev_data, pCreateInfo);
8985208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    for (uint32_t i = 0; i < pCreateInfo->dependencyCount; ++i) {
89863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateStageMaskGsTsEnables(dev_data, pCreateInfo->pDependencies[i].srcStageMask, "vkCreateRenderPass()",
8987315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                             VALIDATION_ERROR_13e006b8, VALIDATION_ERROR_13e006bc);
89883251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateStageMaskGsTsEnables(dev_data, pCreateInfo->pDependencies[i].dstStageMask, "vkCreateRenderPass()",
8989315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                             VALIDATION_ERROR_13e006ba, VALIDATION_ERROR_13e006be);
8990208aecf4cb59762be429488d7d4484f138c2cd81Tobin Ehlis    }
89913251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) {
89923251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateLayouts(dev_data, device, pCreateInfo);
8993ab38df28c5ae1816c5fa33c0c7840c6950e83f0dChris Forbes    }
8994ff6101de02d1677fb54962e2ff57875e76898e26Chris Forbes    lock.unlock();
89954f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
89963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) {
89974f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        return VK_ERROR_VALIDATION_FAILED_EXT;
89984f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski    }
89994f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
90004a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateRenderPass(device, pCreateInfo, pAllocator, pRenderPass);
9001ff6101de02d1677fb54962e2ff57875e76898e26Chris Forbes
90025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
90034f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        lock.lock();
90044f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
90054f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        std::vector<bool> has_self_dependency(pCreateInfo->subpassCount);
90064f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski        std::vector<DAGNode> subpass_to_node(pCreateInfo->subpassCount);
900732f68580aa01aab3e923cb52915a1d3dd4e993c5Chris Forbes        skip |= CreatePassDAG(dev_data, pCreateInfo, subpass_to_node, has_self_dependency);
90084f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
9009127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis        auto render_pass = unique_ptr<RENDER_PASS_STATE>(new RENDER_PASS_STATE(pCreateInfo));
901098cddf7090b5d5dcc382045867753ef703d1c3d3Chris Forbes        render_pass->renderPass = *pRenderPass;
9011cf2686cdbb12af8a29ca598c126b5e37215f0ef7Chris Forbes        render_pass->hasSelfDependency = has_self_dependency;
9012cf2686cdbb12af8a29ca598c126b5e37215f0ef7Chris Forbes        render_pass->subpassToNode = subpass_to_node;
9013db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes
901487e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis        for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
901587e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis            const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
901687e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis            for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
90175245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                MarkAttachmentFirstUse(render_pass.get(), subpass.pColorAttachments[j].attachment, false);
90189cde292b1c19c643b7c13018d9834cccfe6ef7eaChris Forbes
90195245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                // resolve attachments are considered to be written
90205245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                if (subpass.pResolveAttachments) {
90215245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                    MarkAttachmentFirstUse(render_pass.get(), subpass.pResolveAttachments[j].attachment, false);
90229cde292b1c19c643b7c13018d9834cccfe6ef7eaChris Forbes                }
902387e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis            }
90245245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes            if (subpass.pDepthStencilAttachment) {
90255245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                MarkAttachmentFirstUse(render_pass.get(), subpass.pDepthStencilAttachment->attachment, false);
902687e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis            }
9027a5ce96d7c88653668a2b33a6b72bd3cb16d73f48Michael Lentine            for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
90285245a74f239ad662d9ca3675789ad41f37424ce6Chris Forbes                MarkAttachmentFirstUse(render_pass.get(), subpass.pInputAttachments[j].attachment, true);
9029a5ce96d7c88653668a2b33a6b72bd3cb16d73f48Michael Lentine            }
903087e0afcd98dcf3c1e5e2cbb3023fe89d9dd10cd2Tobin Ehlis        }
9031db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes
9032fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes        dev_data->renderPassMap[*pRenderPass] = std::move(render_pass);
90335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
90345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
90355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
90364f76794409854faf16dd51f37d5fa21dff1c5d44Mark Lobodzinski
9037eb4c61477130f69f48fdf3ac31cb82104181cc73Chris Forbesstatic bool validatePrimaryCommandBuffer(const layer_data *dev_data, const GLOBAL_CB_NODE *pCB, char const *cmd_name,
90389bd94c6fc216a1d67d5e98542519002fa56d19dbMike Schuchardt                                         UNIQUE_VALIDATION_ERROR_CODE error_code) {
90393251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
90405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
90413251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
90429b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(pCB->commandBuffer), __LINE__, error_code, "DS",
90439b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        "Cannot execute command %s on a secondary command buffer. %s", cmd_name, validation_error_map[error_code]);
90445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
90453251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
90465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
90475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
90488860b85a52096f9f9b28616bc37feed505497a54Chris Forbesstatic bool VerifyRenderAreaBounds(const layer_data *dev_data, const VkRenderPassBeginInfo *pRenderPassBegin) {
90493251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
9050c54e405a4ce05f4de10bb78bfc3a4769c41d2d59Tobin Ehlis    const safe_VkFramebufferCreateInfo *pFramebufferInfo =
90519a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        &GetFramebufferState(dev_data, pRenderPassBegin->framebuffer)->createInfo;
9052885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine    if (pRenderPassBegin->renderArea.offset.x < 0 ||
9053885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine        (pRenderPassBegin->renderArea.offset.x + pRenderPassBegin->renderArea.extent.width) > pFramebufferInfo->width ||
9054885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine        pRenderPassBegin->renderArea.offset.y < 0 ||
9055885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine        (pRenderPassBegin->renderArea.offset.y + pRenderPassBegin->renderArea.extent.height) > pFramebufferInfo->height) {
90563251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= static_cast<bool>(log_msg(
9057df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
9058885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            DRAWSTATE_INVALID_RENDER_AREA, "CORE",
9059885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            "Cannot execute a render pass with renderArea not within the bound of the "
9060885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            "framebuffer. RenderArea: x %d, y %d, width %d, height %d. Framebuffer: width %d, "
9061885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            "height %d.",
9062885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            pRenderPassBegin->renderArea.offset.x, pRenderPassBegin->renderArea.offset.y, pRenderPassBegin->renderArea.extent.width,
9063885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine            pRenderPassBegin->renderArea.extent.height, pFramebufferInfo->width, pFramebufferInfo->height));
9064885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine    }
90653251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
9066885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine}
9067885537d813d6fb3d199e76f6d63b6d3f78d0eeb0Michael Lentine
90681a65650f856376768d7b03ea2d080aaff87cacfdMark 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
90691a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski// [load|store]Op flag must be checked
90701a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski// TODO: The memory valid flag in DEVICE_MEM_INFO should probably be split to track the validity of stencil memory separately.
9071cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskitemplate <typename T>
9072cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinskistatic bool FormatSpecificLoadAndStoreOpSettings(VkFormat format, T color_depth_op, T stencil_op, T op) {
9073a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski    if (color_depth_op != op && stencil_op != op) {
9074a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski        return false;
9075a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski    }
907616769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton    bool check_color_depth_load_op = !FormatIsStencilOnly(format);
907716769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton    bool check_stencil_load_op = FormatIsDepthAndStencil(format) || !check_color_depth_load_op;
9078a49b8a211ce07e7fa2225d23f8cb11f1055b418aMark Lobodzinski
90790d9453d85335963d6cabfbf400b058dc905ea238Chris Forbes    return ((check_color_depth_load_op && (color_depth_op == op)) ||
90800d9453d85335963d6cabfbf400b058dc905ea238Chris Forbes            (check_stencil_load_op && (stencil_op == op)));
90811a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski}
90821a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski
9083bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
9084bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              VkSubpassContents contents) {
90853251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
908656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
9087b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
90889a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *cb_node = GetCBNode(dev_data, commandBuffer);
90899a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto render_pass_state = pRenderPassBegin ? GetRenderPassState(dev_data, pRenderPassBegin->renderPass) : nullptr;
90909a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto framebuffer = pRenderPassBegin ? GetFramebufferState(dev_data, pRenderPassBegin->framebuffer) : nullptr;
9091f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis    if (cb_node) {
9092308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski        if (render_pass_state) {
9093cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            uint32_t clear_op_size = 0;  // Make sure pClearValues is at least as large as last LOAD_OP_CLEAR
9094f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->activeFramebuffer = pRenderPassBegin->framebuffer;
9095308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski            for (uint32_t i = 0; i < render_pass_state->createInfo.attachmentCount; ++i) {
9096f40ab6d10b8d755ce0e461c33916b0d4d5a5d437Chris Forbes                MT_FB_ATTACHMENT_INFO &fb_info = framebuffer->attachments[i];
9097308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski                auto pAttachment = &render_pass_state->createInfo.pAttachments[i];
9098bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->loadOp, pAttachment->stencilLoadOp,
90991a65650f856376768d7b03ea2d080aaff87cacfdMark Lobodzinski                                                         VK_ATTACHMENT_LOAD_OP_CLEAR)) {
910092bc0680357019834b7529148ab6d73353ce02c7Mark Lobodzinski                    clear_op_size = static_cast<uint32_t>(i) + 1;
910116387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    std::function<bool()> function = [=]() {
91029a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        SetImageMemoryValid(dev_data, GetImageState(dev_data, fb_info.image), true);
910316387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                        return false;
910416387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    };
9105f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                    cb_node->validate_functions.push_back(function);
9106db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes                } else if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->loadOp,
9107bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                pAttachment->stencilLoadOp, VK_ATTACHMENT_LOAD_OP_DONT_CARE)) {
910816387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    std::function<bool()> function = [=]() {
91099a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        SetImageMemoryValid(dev_data, GetImageState(dev_data, fb_info.image), false);
911016387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                        return false;
911116387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    };
9112f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                    cb_node->validate_functions.push_back(function);
9113db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes                } else if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->loadOp,
9114bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                pAttachment->stencilLoadOp, VK_ATTACHMENT_LOAD_OP_LOAD)) {
911516387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    std::function<bool()> function = [=]() {
91169a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        return ValidateImageMemoryIsValid(dev_data, GetImageState(dev_data, fb_info.image),
9117f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis                                                          "vkCmdBeginRenderPass()");
911816387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    };
9119f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                    cb_node->validate_functions.push_back(function);
912016387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                }
9121308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski                if (render_pass_state->attachment_first_read[i]) {
912216387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    std::function<bool()> function = [=]() {
91239a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        return ValidateImageMemoryIsValid(dev_data, GetImageState(dev_data, fb_info.image),
9124f989de4217bce0f293121d0da53dc8328276370fTobin Ehlis                                                          "vkCmdBeginRenderPass()");
912516387282d11e414ae7cb9ddf3d0c1bebf8f2c74dChris Forbes                    };
9126f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis                    cb_node->validate_functions.push_back(function);
91275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
91285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
91296de3c6ffa0819ee37cd5cecee918b062145e2ff1Tobin Ehlis            if (clear_op_size > pRenderPassBegin->clearValueCount) {
91303251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(
9131369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan                    dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
9132315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                    HandleToUint64(render_pass_state->renderPass), __LINE__, VALIDATION_ERROR_1200070c, "DS",
9133bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "In vkCmdBeginRenderPass() the VkRenderPassBeginInfo struct has a clearValueCount of %u but there must "
9134bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "be at least %u entries in pClearValues array to account for the highest index attachment in renderPass "
9135cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "0x%" PRIx64
9136cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    " that uses VK_ATTACHMENT_LOAD_OP_CLEAR is %u. Note that the pClearValues array "
9137bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "is indexed by attachment number so even if some pClearValues entries between 0 and %u correspond to "
9138bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    "attachments that aren't cleared they will be ignored. %s",
91399b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    pRenderPassBegin->clearValueCount, clear_op_size, HandleToUint64(render_pass_state->renderPass), clear_op_size,
9140315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                    clear_op_size - 1, validation_error_map[VALIDATION_ERROR_1200070c]);
9141369cf6deef1fca74f9eb1f8ef6e96deba715b133Slawomir Cygan            }
91423251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= VerifyRenderAreaBounds(dev_data, pRenderPassBegin);
91433251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= VerifyFramebufferAndRenderPassLayouts(dev_data, cb_node, pRenderPassBegin,
91443251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                          GetFramebufferState(dev_data, pRenderPassBegin->framebuffer));
9145315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            skip |= insideRenderPass(dev_data, cb_node, "vkCmdBeginRenderPass()", VALIDATION_ERROR_17a00017);
91463251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= ValidateDependencies(dev_data, framebuffer, render_pass_state);
9147315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            skip |= validatePrimaryCommandBuffer(dev_data, cb_node, "vkCmdBeginRenderPass()", VALIDATION_ERROR_17a00019);
9148315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            skip |= ValidateCmdQueueFlags(dev_data, cb_node, "vkCmdBeginRenderPass()", VK_QUEUE_GRAPHICS_BIT,
9149315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                          VALIDATION_ERROR_17a02415);
91503251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= ValidateCmd(dev_data, cb_node, CMD_BEGINRENDERPASS, "vkCmdBeginRenderPass()");
91511ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis            UpdateCmdBufferLastCmd(cb_node, CMD_BEGINRENDERPASS);
9152308153fd68fc050a302201fb5a7cca53de8dc866Mark Lobodzinski            cb_node->activeRenderPass = render_pass_state;
91535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // This is a shallow copy as that is all that is needed for now
9154f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->activeRenderPassBeginInfo = *pRenderPassBegin;
9155f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->activeSubpass = 0;
9156f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->activeSubpassContents = contents;
9157f909505280723ee24d2e74afc759d38dc09a37beTobin Ehlis            cb_node->framebuffers.insert(pRenderPassBegin->framebuffer);
9158883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis            // Connect this framebuffer and its children to this cmdBuffer
9159883ee3f865f9dbd83134d148b26e96cb6a926b3dTobin Ehlis            AddFramebufferBinding(dev_data, cb_node, framebuffer);
91605f025a7d647e3257e12a816fa1db078b5fc8ed49Tobin Ehlis            // transition attachments to the correct layouts for beginning of renderPass and first subpass
91615f025a7d647e3257e12a816fa1db078b5fc8ed49Tobin Ehlis            TransitionBeginRenderPassLayouts(dev_data, cb_node, render_pass_state, framebuffer);
91625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
91635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9164b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
91653251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) {
91664a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.CmdBeginRenderPass(commandBuffer, pRenderPassBegin, contents);
91675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
91685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
91695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
917089d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents) {
91713251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
917256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
9173b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
91749a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
91755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
9176315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdNextSubpass()", VALIDATION_ERROR_1b600019);
9177315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdNextSubpass()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1b602415);
91783251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_NEXTSUBPASS, "vkCmdNextSubpass()");
91791ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_NEXTSUBPASS);
9180315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= outsideRenderPass(dev_data, pCB, "vkCmdNextSubpass()", VALIDATION_ERROR_1b600017);
918180281691386b37385846f21b38e8c9d4b12cc74eChris Forbes
9182fb13c2c4174108223d9f8e43084020eb09115ed6Chris Forbes        auto subpassCount = pCB->activeRenderPass->createInfo.subpassCount;
918380281691386b37385846f21b38e8c9d4b12cc74eChris Forbes        if (pCB->activeSubpass == subpassCount - 1) {
91843251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9185315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_1b60071a, "DS",
91863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkCmdNextSubpass(): Attempted to advance beyond final subpass. %s",
9187315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_1b60071a]);
918880281691386b37385846f21b38e8c9d4b12cc74eChris Forbes        }
91895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9190b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
919196ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes
91923251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return;
919396ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes
91944a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.CmdNextSubpass(commandBuffer, contents);
919596ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes
919696ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes    if (pCB) {
9197bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        lock.lock();
9198bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pCB->activeSubpass++;
9199bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pCB->activeSubpassContents = contents;
92005f025a7d647e3257e12a816fa1db078b5fc8ed49Tobin Ehlis        TransitionSubpassLayouts(dev_data, pCB, pCB->activeRenderPass, pCB->activeSubpass,
92019a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                                 GetFramebufferState(dev_data, pCB->activeRenderPassBeginInfo.framebuffer));
920296ebb1e373cc0993339e2ecc1dc47e9918406f87Chris Forbes    }
92035b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
92045b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
920589d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL CmdEndRenderPass(VkCommandBuffer commandBuffer) {
92063251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
920756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
9208b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
92099a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pCB = GetCBNode(dev_data, commandBuffer);
921055867dbad6ae423b3bd78c15f6771031a710b5adMark Lobodzinski    FRAMEBUFFER_STATE *framebuffer = NULL;
921158c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes    if (pCB) {
9212127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis        RENDER_PASS_STATE *rp_state = pCB->activeRenderPass;
92139a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        framebuffer = GetFramebufferState(dev_data, pCB->activeFramebuffer);
9214127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis        if (rp_state) {
9215127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis            if (pCB->activeSubpass != rp_state->createInfo.subpassCount - 1) {
92163251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
92179b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(commandBuffer), __LINE__,
9218315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                VALIDATION_ERROR_1b00071c, "DS", "vkCmdEndRenderPass(): Called before reaching final subpass. %s",
9219315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                validation_error_map[VALIDATION_ERROR_1b00071c]);
922002a3382f28fc7c6ec6018165be88aa6fc4f05c9eChris Forbes            }
922102a3382f28fc7c6ec6018165be88aa6fc4f05c9eChris Forbes
9222127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis            for (size_t i = 0; i < rp_state->createInfo.attachmentCount; ++i) {
9223e3ad4b1284408353cc56a04951c1df1f35a636ceChris Forbes                MT_FB_ATTACHMENT_INFO &fb_info = framebuffer->attachments[i];
9224127937bcdb5817ee4568887c298ce36c88f3c58bTobin Ehlis                auto pAttachment = &rp_state->createInfo.pAttachments[i];
9225bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->storeOp, pAttachment->stencilStoreOp,
9226bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                         VK_ATTACHMENT_STORE_OP_STORE)) {
922758c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    std::function<bool()> function = [=]() {
92289a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        SetImageMemoryValid(dev_data, GetImageState(dev_data, fb_info.image), true);
922958c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                        return false;
923058c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    };
923158c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    pCB->validate_functions.push_back(function);
9232db6ad16f7690669bb664b970a8e5c47abb8db9faChris Forbes                } else if (FormatSpecificLoadAndStoreOpSettings(pAttachment->format, pAttachment->storeOp,
9233bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                pAttachment->stencilStoreOp, VK_ATTACHMENT_STORE_OP_DONT_CARE)) {
923458c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    std::function<bool()> function = [=]() {
92359a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                        SetImageMemoryValid(dev_data, GetImageState(dev_data, fb_info.image), false);
923658c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                        return false;
923758c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    };
923858c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes                    pCB->validate_functions.push_back(function);
92395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
92405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
92415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
9242315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= outsideRenderPass(dev_data, pCB, "vkCmdEndRenderpass()", VALIDATION_ERROR_1b000017);
9243315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdEndRenderPass()", VALIDATION_ERROR_1b000019);
9244315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= ValidateCmdQueueFlags(dev_data, pCB, "vkCmdEndRenderPass()", VK_QUEUE_GRAPHICS_BIT, VALIDATION_ERROR_1b002415);
92453251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateCmd(dev_data, pCB, CMD_ENDRENDERPASS, "vkCmdEndRenderPass()");
92461ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_ENDRENDERPASS);
92470e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes    }
92480e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes    lock.unlock();
92490e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes
92503251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return;
92510e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes
92524a0754042cf090e131e9e769d8a3633c228625beChris Forbes    dev_data->dispatch_table.CmdEndRenderPass(commandBuffer);
92530e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes
92540e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes    if (pCB) {
92550e21dda98453b5ced1fe7a2ffd5ca4b21847fe09Chris Forbes        lock.lock();
925655867dbad6ae423b3bd78c15f6771031a710b5adMark Lobodzinski        TransitionFinalSubpassLayouts(dev_data, pCB, &pCB->activeRenderPassBeginInfo, framebuffer);
925758c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes        pCB->activeRenderPass = nullptr;
925858c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes        pCB->activeSubpass = 0;
925958c3d40b47b6b30c1e7c508ec14ee67fcd238c93Chris Forbes        pCB->activeFramebuffer = VK_NULL_HANDLE;
92605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
92615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
92625b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9263a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlisstatic bool logInvalidAttachmentMessage(layer_data *dev_data, VkCommandBuffer secondaryBuffer, uint32_t primaryAttach,
9264a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                        uint32_t secondaryAttach, const char *msg) {
9265df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski    return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9266315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                   HandleToUint64(secondaryBuffer), __LINE__, VALIDATION_ERROR_1b2000c4, "DS",
9267df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                   "vkCmdExecuteCommands() called w/ invalid Secondary Cmd Buffer 0x%" PRIx64
9268df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                   " which has a render pass "
9269df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                   "that is not compatible with the Primary Cmd Buffer current render pass. "
9270df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                   "Attachment %u is not compatible with %u: %s. %s",
92719b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                   HandleToUint64(secondaryBuffer), primaryAttach, secondaryAttach, msg,
9272315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                   validation_error_map[VALIDATION_ERROR_1b2000c4]);
92735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
92745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9275a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlisstatic bool validateAttachmentCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer,
9276a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                            VkRenderPassCreateInfo const *primaryPassCI, uint32_t primaryAttach,
9277a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                            VkCommandBuffer secondaryBuffer, VkRenderPassCreateInfo const *secondaryPassCI,
9278e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                                            uint32_t secondaryAttach, bool is_multi) {
92793251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
9280a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (primaryPassCI->attachmentCount <= primaryAttach) {
92815b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        primaryAttach = VK_ATTACHMENT_UNUSED;
92825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9283a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (secondaryPassCI->attachmentCount <= secondaryAttach) {
92845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        secondaryAttach = VK_ATTACHMENT_UNUSED;
92855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
92865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (primaryAttach == VK_ATTACHMENT_UNUSED && secondaryAttach == VK_ATTACHMENT_UNUSED) {
92873251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        return skip;
92885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
92895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (primaryAttach == VK_ATTACHMENT_UNUSED) {
92903251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach,
92913251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            "The first is unused while the second is not.");
92923251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        return skip;
92935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
92945b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (secondaryAttach == VK_ATTACHMENT_UNUSED) {
92953251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach,
92963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            "The second is unused while the first is not.");
92973251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        return skip;
92985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9299a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (primaryPassCI->pAttachments[primaryAttach].format != secondaryPassCI->pAttachments[secondaryAttach].format) {
93003251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |=
9301a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis            logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach, "They have different formats.");
93025b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9303a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (primaryPassCI->pAttachments[primaryAttach].samples != secondaryPassCI->pAttachments[secondaryAttach].samples) {
93043251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |=
9305a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis            logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach, "They have different samples.");
93065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9307a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (is_multi && primaryPassCI->pAttachments[primaryAttach].flags != secondaryPassCI->pAttachments[secondaryAttach].flags) {
93083251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |=
9309a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis            logInvalidAttachmentMessage(dev_data, secondaryBuffer, primaryAttach, secondaryAttach, "They have different flags.");
93105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
93113251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
93125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
93135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9314a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlisstatic bool validateSubpassCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer,
9315a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                         VkRenderPassCreateInfo const *primaryPassCI, VkCommandBuffer secondaryBuffer,
9316a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                         VkRenderPassCreateInfo const *secondaryPassCI, const int subpass, bool is_multi) {
93173251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
9318a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    const VkSubpassDescription &primary_desc = primaryPassCI->pSubpasses[subpass];
9319a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    const VkSubpassDescription &secondary_desc = secondaryPassCI->pSubpasses[subpass];
93205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t maxInputAttachmentCount = std::max(primary_desc.inputAttachmentCount, secondary_desc.inputAttachmentCount);
93215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < maxInputAttachmentCount; ++i) {
93225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primary_input_attach = VK_ATTACHMENT_UNUSED, secondary_input_attach = VK_ATTACHMENT_UNUSED;
93235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < primary_desc.inputAttachmentCount) {
93245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            primary_input_attach = primary_desc.pInputAttachments[i].attachment;
93255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
93265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < secondary_desc.inputAttachmentCount) {
93275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            secondary_input_attach = secondary_desc.pInputAttachments[i].attachment;
93285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
93293251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPassCI, primary_input_attach, secondaryBuffer,
93303251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                secondaryPassCI, secondary_input_attach, is_multi);
93315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
93325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t maxColorAttachmentCount = std::max(primary_desc.colorAttachmentCount, secondary_desc.colorAttachmentCount);
93335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < maxColorAttachmentCount; ++i) {
93345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primary_color_attach = VK_ATTACHMENT_UNUSED, secondary_color_attach = VK_ATTACHMENT_UNUSED;
93355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < primary_desc.colorAttachmentCount) {
93365b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            primary_color_attach = primary_desc.pColorAttachments[i].attachment;
93375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
93385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < secondary_desc.colorAttachmentCount) {
93395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            secondary_color_attach = secondary_desc.pColorAttachments[i].attachment;
93405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
93413251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPassCI, primary_color_attach, secondaryBuffer,
93423251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                secondaryPassCI, secondary_color_attach, is_multi);
93435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        uint32_t primary_resolve_attach = VK_ATTACHMENT_UNUSED, secondary_resolve_attach = VK_ATTACHMENT_UNUSED;
93445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < primary_desc.colorAttachmentCount && primary_desc.pResolveAttachments) {
93455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            primary_resolve_attach = primary_desc.pResolveAttachments[i].attachment;
93465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
93475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (i < secondary_desc.colorAttachmentCount && secondary_desc.pResolveAttachments) {
93485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            secondary_resolve_attach = secondary_desc.pResolveAttachments[i].attachment;
93495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
93503251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPassCI, primary_resolve_attach, secondaryBuffer,
93513251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                secondaryPassCI, secondary_resolve_attach, is_multi);
93525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
93535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    uint32_t primary_depthstencil_attach = VK_ATTACHMENT_UNUSED, secondary_depthstencil_attach = VK_ATTACHMENT_UNUSED;
93545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (primary_desc.pDepthStencilAttachment) {
93555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        primary_depthstencil_attach = primary_desc.pDepthStencilAttachment[0].attachment;
93565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
93575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (secondary_desc.pDepthStencilAttachment) {
93585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        secondary_depthstencil_attach = secondary_desc.pDepthStencilAttachment[0].attachment;
93595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
93603251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPassCI, primary_depthstencil_attach, secondaryBuffer,
93613251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                            secondaryPassCI, secondary_depthstencil_attach, is_multi);
93623251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
93635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
93645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9365a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis// Verify that given renderPass CreateInfo for primary and secondary command buffers are compatible.
9366a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis//  This function deals directly with the CreateInfo, there are overloaded versions below that can take the renderPass handle and
9367a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis//  will then feed into this function
9368a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlisstatic bool validateRenderPassCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer,
9369a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                            VkRenderPassCreateInfo const *primaryPassCI, VkCommandBuffer secondaryBuffer,
9370a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                                            VkRenderPassCreateInfo const *secondaryPassCI) {
93713251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
9372a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis
9373a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    if (primaryPassCI->subpassCount != secondaryPassCI->subpassCount) {
93743251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
93759b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(primaryBuffer), __LINE__, DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
93763251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkCmdExecuteCommands() called w/ invalid secondary Cmd Buffer 0x%" PRIx64
93773251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        " that has a subpassCount of %u that is incompatible with the primary Cmd Buffer 0x%" PRIx64
93783251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        " that has a subpassCount of %u.",
93799b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(secondaryBuffer), secondaryPassCI->subpassCount, HandleToUint64(primaryBuffer),
93809b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        primaryPassCI->subpassCount);
9381a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis    } else {
9382a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        for (uint32_t i = 0; i < primaryPassCI->subpassCount; ++i) {
93833251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= validateSubpassCompatibility(dev_data, primaryBuffer, primaryPassCI, secondaryBuffer, secondaryPassCI, i,
93843251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                 primaryPassCI->subpassCount > 1);
9385a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        }
93865b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
93873251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
93885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
93895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9390e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool validateFramebuffer(layer_data *dev_data, VkCommandBuffer primaryBuffer, const GLOBAL_CB_NODE *pCB,
9391e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                                VkCommandBuffer secondaryBuffer, const GLOBAL_CB_NODE *pSubCB) {
93923251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
93935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (!pSubCB->beginInfo.pInheritanceInfo) {
93943251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        return skip;
93955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9396c5b97dda856ff837638b3ebb7e231d5507c495a3Chris Forbes    VkFramebuffer primary_fb = pCB->activeFramebuffer;
93975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkFramebuffer secondary_fb = pSubCB->beginInfo.pInheritanceInfo->framebuffer;
93985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (secondary_fb != VK_NULL_HANDLE) {
93995b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (primary_fb != secondary_fb) {
94003251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9401315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(primaryBuffer), __LINE__, VALIDATION_ERROR_1b2000c6, "DS",
94023251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkCmdExecuteCommands() called w/ invalid secondary command buffer 0x%" PRIx64
94033251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            " which has a framebuffer 0x%" PRIx64
94043251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            " that is not the same as the primary command buffer's current active framebuffer 0x%" PRIx64 ". %s",
94059b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(secondaryBuffer), HandleToUint64(secondary_fb), HandleToUint64(primary_fb),
9406315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_1b2000c6]);
94075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
94089a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto fb = GetFramebufferState(dev_data, secondary_fb);
9409e3ad4b1284408353cc56a04951c1df1f35a636ceChris Forbes        if (!fb) {
94103251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
94119b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(primaryBuffer), __LINE__, DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
94123251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "vkCmdExecuteCommands() called w/ invalid Cmd Buffer 0x%p "
94133251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "which has invalid framebuffer 0x%" PRIx64 ".",
94149b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            (void *)secondaryBuffer, HandleToUint64(secondary_fb));
94153251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            return skip;
94165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
94179a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto cb_renderpass = GetRenderPassState(dev_data, pSubCB->beginInfo.pInheritanceInfo->renderPass);
9418a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        if (cb_renderpass->renderPass != fb->createInfo.renderPass) {
94193251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= validateRenderPassCompatibility(dev_data, secondaryBuffer, fb->renderPassCreateInfo.ptr(), secondaryBuffer,
94203251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                    cb_renderpass->createInfo.ptr());
9421a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis        }
94225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
94233251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
94245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
94255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9426e3319189d6f8e3126522df7a5935d2c42f656291Dustin Gravesstatic bool validateSecondaryCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB, GLOBAL_CB_NODE *pSubCB) {
94273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
94285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    unordered_set<int> activeTypes;
94295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto queryObject : pCB->activeQueries) {
94305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto queryPoolData = dev_data->queryPoolMap.find(queryObject.pool);
94315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (queryPoolData != dev_data->queryPoolMap.end()) {
94325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (queryPoolData->second.createInfo.queryType == VK_QUERY_TYPE_PIPELINE_STATISTICS &&
94335b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                pSubCB->beginInfo.pInheritanceInfo) {
94345b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                VkQueryPipelineStatisticFlags cmdBufStatistics = pSubCB->beginInfo.pInheritanceInfo->pipelineStatistics;
94355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if ((cmdBufStatistics & queryPoolData->second.createInfo.pipelineStatistics) != cmdBufStatistics) {
94369b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    skip |= log_msg(
94379b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9438315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(pCB->commandBuffer), __LINE__, VALIDATION_ERROR_1b2000d0, "DS",
94399b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        "vkCmdExecuteCommands() called w/ invalid Cmd Buffer 0x%p "
94409b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        "which has invalid active query pool 0x%" PRIx64
94419b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        ". Pipeline statistics is being queried so the command "
94429b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        "buffer must have all bits set on the queryPool. %s",
9443315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        pCB->commandBuffer, HandleToUint64(queryPoolData->first), validation_error_map[VALIDATION_ERROR_1b2000d0]);
94445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
94455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
94465b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            activeTypes.insert(queryPoolData->second.createInfo.queryType);
94475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
94485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
94495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (auto queryObject : pSubCB->startedQueries) {
94505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        auto queryPoolData = dev_data->queryPoolMap.find(queryObject.pool);
94515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        if (queryPoolData != dev_data->queryPoolMap.end() && activeTypes.count(queryPoolData->second.createInfo.queryType)) {
94529b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
94539b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
94549b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "vkCmdExecuteCommands() called w/ invalid Cmd Buffer 0x%p "
94559b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "which has invalid active query pool 0x%" PRIx64
94569b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "of type %d but a query of that type has been started on "
94579b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "secondary Cmd Buffer 0x%p.",
94589b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            pCB->commandBuffer, HandleToUint64(queryPoolData->first), queryPoolData->second.createInfo.queryType,
94599b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            pSubCB->commandBuffer);
94605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
94615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
94627bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
94639a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto primary_pool = GetCommandPoolNode(dev_data, pCB->createInfo.commandPool);
94649a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto secondary_pool = GetCommandPoolNode(dev_data, pSubCB->createInfo.commandPool);
94657bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski    if (primary_pool && secondary_pool && (primary_pool->queueFamilyIndex != secondary_pool->queueFamilyIndex)) {
94663251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |=
9467226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
94689b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    HandleToUint64(pSubCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_QUEUE_FAMILY, "DS",
9469226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    "vkCmdExecuteCommands(): Primary command buffer 0x%p"
9470226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    " created in queue family %d has secondary command buffer 0x%p created in queue family %d.",
9471226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                    pCB->commandBuffer, primary_pool->queueFamilyIndex, pSubCB->commandBuffer, secondary_pool->queueFamilyIndex);
94727bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski    }
94737bd96b29f4b8df99339ff1f7bc64f2f8940f8d25Mark Lobodzinski
94743251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    return skip;
94755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
94765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9477bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBuffersCount,
9478bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                              const VkCommandBuffer *pCommandBuffers) {
94793251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
948056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
9481b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
94829a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    GLOBAL_CB_NODE *pCB = GetCBNode(dev_data, commandBuffer);
94835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (pCB) {
94845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        GLOBAL_CB_NODE *pSubCB = NULL;
94855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < commandBuffersCount; i++) {
94869a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            pSubCB = GetCBNode(dev_data, pCommandBuffers[i]);
94870a8b955c23012196339f3c10ffedc631ea0f7c58Tobin Ehlis            assert(pSubCB);
94880a8b955c23012196339f3c10ffedc631ea0f7c58Tobin Ehlis            if (VK_COMMAND_BUFFER_LEVEL_PRIMARY == pSubCB->createInfo.level) {
94893251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
9490df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9491315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(pCommandBuffers[i]), __LINE__, VALIDATION_ERROR_1b2000b0, "DS",
9492df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "vkCmdExecuteCommands() called w/ Primary Cmd Buffer 0x%p in element %u of pCommandBuffers "
9493df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski                            "array. All cmd buffers in pCommandBuffers array must be secondary. %s",
9494315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            pCommandBuffers[i], i, validation_error_map[VALIDATION_ERROR_1b2000b0]);
9495cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            } else if (pCB->activeRenderPass) {  // Secondary CB w/i RenderPass must have *CONTINUE_BIT set
94960de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                if (pSubCB->beginInfo.pInheritanceInfo != nullptr) {
94970de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                    auto secondary_rp_state = GetRenderPassState(dev_data, pSubCB->beginInfo.pInheritanceInfo->renderPass);
94980de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                    if (!(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
94990de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                        skip |= log_msg(
95000de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9501315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(pCommandBuffers[i]), __LINE__, VALIDATION_ERROR_1b2000c0, "DS",
95020de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            "vkCmdExecuteCommands(): Secondary Command Buffer (0x%p) executed within render pass (0x%" PRIxLEAST64
95030de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            ") must have had vkBeginCommandBuffer() called w/ VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT "
95040de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            "set. %s",
95050de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            pCommandBuffers[i], HandleToUint64(pCB->activeRenderPass->renderPass),
9506315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_1b2000c0]);
95070de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                    } else {
95080de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                        // Make sure render pass is compatible with parent command buffer pass if has continue
95090de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                        if (pCB->activeRenderPass->renderPass != secondary_rp_state->renderPass) {
95100de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            skip |=
95110de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                                validateRenderPassCompatibility(dev_data, commandBuffer, pCB->activeRenderPass->createInfo.ptr(),
95123251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                                                pCommandBuffers[i], secondary_rp_state->createInfo.ptr());
95130de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                        }
95140de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                        //  If framebuffer for secondary CB is not NULL, then it must match active FB from primaryCB
95150de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                        skip |= validateFramebuffer(dev_data, commandBuffer, pCB, pCommandBuffers[i], pSubCB);
95160de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                    }
95170de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                    string errorString = "";
95180de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                    // secondaryCB must have been created w/ RP compatible w/ primaryCB active renderpass
95190de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                    if ((pCB->activeRenderPass->renderPass != secondary_rp_state->renderPass) &&
95200de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                        !verify_renderpass_compatibility(dev_data, pCB->activeRenderPass->createInfo.ptr(),
95210de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                                                         secondary_rp_state->createInfo.ptr(), errorString)) {
95220de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                        skip |= log_msg(
95230de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
95240de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            HandleToUint64(pCommandBuffers[i]), __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE, "DS",
95250de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            "vkCmdExecuteCommands(): Secondary Command Buffer (0x%p) w/ render pass (0x%" PRIxLEAST64
95260de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            ") is incompatible w/ primary command buffer (0x%p) w/ render pass (0x%" PRIxLEAST64 ") due to: %s",
95270de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            pCommandBuffers[i], HandleToUint64(pSubCB->beginInfo.pInheritanceInfo->renderPass), commandBuffer,
95280de5f3bbf5218c9bc92c5bb09c8547bd26adcabcMark Lobodzinski                            HandleToUint64(pCB->activeRenderPass->renderPass), errorString.c_str());
9529a092085c225bbc24edb29cd34ca6b30889f7e111Tobin Ehlis                    }
95305b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
95315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
95325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            // TODO(mlentine): Move more logic into this method
95333251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= validateSecondaryCommandBufferState(dev_data, pCB, pSubCB);
9534315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            skip |= validateCommandBufferState(dev_data, pSubCB, "vkCmdExecuteCommands()", 0, VALIDATION_ERROR_1b2000b2);
95355b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            if (!(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
95369b2582dc67737351a72fbeb82e9e6e8cdff7a026Chris Forbes                if (pSubCB->in_use.load() || pCB->linkedCommandBuffers.count(pSubCB)) {
95373251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
95389b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(pCB->commandBuffer), __LINE__,
9539315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    VALIDATION_ERROR_1b2000b4, "DS",
95403251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "Attempt to simultaneously execute command buffer 0x%p"
95413251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    " without VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set! %s",
9542315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                    pCB->commandBuffer, validation_error_map[VALIDATION_ERROR_1b2000b4]);
95435b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
95445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT) {
95455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    // Warn that non-simultaneous secondary cmd buffer renders primary non-simultaneous
95463251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(
95475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
95489b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(pCommandBuffers[i]), __LINE__, DRAWSTATE_INVALID_CB_SIMULTANEOUS_USE, "DS",
9549226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "vkCmdExecuteCommands(): Secondary Command Buffer (0x%p) "
9550226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set and will cause primary command buffer "
9551226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        "(0x%p) to be treated as if it does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT "
955283b40cb743b7d87753e7503b148fef660ca45289Tobin Ehlis                        "set, even though it does.",
9553226a75bff897619b86cc227cf1196b5e245fb96dTobin Ehlis                        pCommandBuffers[i], pCB->commandBuffer);
95545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    pCB->beginInfo.flags &= ~VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
95555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
95565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
9557f71dd305f197826a61f398bff725267a20ea1d90Chris Forbes            if (!pCB->activeQueries.empty() && !dev_data->enabled_features.inheritedQueries) {
95583251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
9559cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9560315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(pCommandBuffers[i]), __LINE__, VALIDATION_ERROR_1b2000ca, "DS",
9561cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "vkCmdExecuteCommands(): Secondary Command Buffer "
9562cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "(0x%p) cannot be submitted with a query in "
9563cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "flight and inherited queries not "
9564cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                            "supported on this device. %s",
9565315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            pCommandBuffers[i], validation_error_map[VALIDATION_ERROR_1b2000ca]);
95665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
95679b2582dc67737351a72fbeb82e9e6e8cdff7a026Chris Forbes            // TODO: separate validate from update! This is very tangled.
95688567fecbf563420f5900ade277ca68908aa87259Tobin Ehlis            // Propagate layout transitions to the primary cmd buffer
95698567fecbf563420f5900ade277ca68908aa87259Tobin Ehlis            for (auto ilm_entry : pSubCB->imageLayoutMap) {
957055867dbad6ae423b3bd78c15f6771031a710b5adMark Lobodzinski                SetLayout(dev_data, pCB, ilm_entry.first, ilm_entry.second);
95718567fecbf563420f5900ade277ca68908aa87259Tobin Ehlis            }
95725b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            pSubCB->primaryCommandBuffer = pCB->commandBuffer;
95731a3660584634742a3297915c94768d73f360e794Chris Forbes            pCB->linkedCommandBuffers.insert(pSubCB);
95741a3660584634742a3297915c94768d73f360e794Chris Forbes            pSubCB->linkedCommandBuffers.insert(pCB);
9575d4ee9fdb2def1e9dc70c5627c9103e264471b8ebMichael Lentine            for (auto &function : pSubCB->queryUpdates) {
9576d4ee9fdb2def1e9dc70c5627c9103e264471b8ebMichael Lentine                pCB->queryUpdates.push_back(function);
9577d4ee9fdb2def1e9dc70c5627c9103e264471b8ebMichael Lentine            }
95785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
9579315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdExecuteCommands()", VALIDATION_ERROR_1b200019);
9580315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis        skip |=
9581315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis            ValidateCmdQueueFlags(dev_data, pCB, "vkCmdExecuteCommands()",
9582315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                  VK_QUEUE_TRANSFER_BIT | VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, VALIDATION_ERROR_1b202415);
9583f5a52627a6576d3d532cd1f2e1be6d9987aeda7fChris Forbes        skip |= ValidateCmd(dev_data, pCB, CMD_EXECUTECOMMANDS, "vkCmdExecuteCommands()");
95841ae739f43f52f7a8bb3a58dcdeac617ddd30b16cTobin Ehlis        UpdateCmdBufferLastCmd(pCB, CMD_EXECUTECOMMANDS);
95855b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9586b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
95873251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.CmdExecuteCommands(commandBuffer, commandBuffersCount, pCommandBuffers);
95885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
95895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9590bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL MapMemory(VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size, VkFlags flags,
9591bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                         void **ppData) {
959256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
95935b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
95943251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
95955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
9596b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
95979a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    DEVICE_MEM_INFO *mem_info = GetMemObjInfo(dev_data, mem);
9598cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis    if (mem_info) {
9599f541bf53dee6daf82a4c8304354eac599a884d29Tobin Ehlis        // TODO : This could me more fine-grained to track just region that is valid
9600f541bf53dee6daf82a4c8304354eac599a884d29Tobin Ehlis        mem_info->global_valid = true;
9601623548a271287ae55415e45e3c654ee66d4e79ffTobin Ehlis        auto end_offset = (VK_WHOLE_SIZE == size) ? mem_info->alloc_info.allocationSize - 1 : offset + size - 1;
96023251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateMapImageLayouts(dev_data, device, mem_info, offset, end_offset);
9603cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis        // TODO : Do we need to create new "bound_range" for the mapped range?
9604623548a271287ae55415e45e3c654ee66d4e79ffTobin Ehlis        SetMemRangesValid(dev_data, mem_info, offset, end_offset);
9605cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis        if ((dev_data->phys_dev_mem_props.memoryTypes[mem_info->alloc_info.memoryTypeIndex].propertyFlags &
9606b1b606d27e8c4179534d7bbb48ce217429e37414Tobin Ehlis             VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) {
96073251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
9608315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                           HandleToUint64(mem), __LINE__, VALIDATION_ERROR_31200554, "MEM",
96093251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                           "Mapping Memory without VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT set: mem obj 0x%" PRIxLEAST64 ". %s",
9610315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                           HandleToUint64(mem), validation_error_map[VALIDATION_ERROR_31200554]);
96115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
96125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
96133251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= ValidateMapMemRange(dev_data, mem, offset, size);
9614b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
96155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
96163251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) {
96174a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.MapMemory(device, mem, offset, size, flags, ppData);
96187c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis        if (VK_SUCCESS == result) {
96197c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis            lock.lock();
9620cf17f50f6489504c0d8151c46d6f77404ce2ffffTobin Ehlis            // TODO : What's the point of this range? See comment on creating new "bound_range" above, which may replace this
96217c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis            storeMemRanges(dev_data, mem, offset, size);
96225f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            initializeAndTrackMemory(dev_data, mem, offset, size, ppData);
96237c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis            lock.unlock();
96247c0012acb5327961b0a5191434a08e5fa788786dTobin Ehlis        }
96255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
96265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
96275b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
96285b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
962989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR void VKAPI_CALL UnmapMemory(VkDevice device, VkDeviceMemory mem) {
963056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
96313251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
96325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9633b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
96343251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= deleteMemRanges(dev_data, mem);
9635b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
96363251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) {
96374a0754042cf090e131e9e769d8a3633c228625beChris Forbes        dev_data->dispatch_table.UnmapMemory(device, mem);
96385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
96395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
96405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
96418860b85a52096f9f9b28616bc37feed505497a54Chris Forbesstatic bool validateMemoryIsMapped(layer_data *dev_data, const char *funcName, uint32_t memRangeCount,
9642e3319189d6f8e3126522df7a5935d2c42f656291Dustin Graves                                   const VkMappedMemoryRange *pMemRanges) {
9643c7ee6f2fe100c1aacfaa0872832717c906bb8a4aMark Lobodzinski    bool skip = false;
96445b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    for (uint32_t i = 0; i < memRangeCount; ++i) {
96459a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto mem_info = GetMemObjInfo(dev_data, pMemRanges[i].memory);
964657fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        if (mem_info) {
9647f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski            if (pMemRanges[i].size == VK_WHOLE_SIZE) {
9648f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                if (mem_info->mem_range.offset > pMemRanges[i].offset) {
9649315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                    skip |=
9650315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
9651315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                HandleToUint64(pMemRanges[i].memory), __LINE__, VALIDATION_ERROR_0c20055c, "MEM",
9652315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                "%s: Flush/Invalidate offset (" PRINTF_SIZE_T_SPECIFIER
9653315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                ") is less than Memory Object's offset "
9654315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                "(" PRINTF_SIZE_T_SPECIFIER "). %s",
9655315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                funcName, static_cast<size_t>(pMemRanges[i].offset),
9656315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                static_cast<size_t>(mem_info->mem_range.offset), validation_error_map[VALIDATION_ERROR_0c20055c]);
9657f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                }
9658f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski            } else {
9659f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                const uint64_t data_end = (mem_info->mem_range.size == VK_WHOLE_SIZE)
9660f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                              ? mem_info->alloc_info.allocationSize
9661f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                              : (mem_info->mem_range.offset + mem_info->mem_range.size);
9662f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                if ((mem_info->mem_range.offset > pMemRanges[i].offset) ||
9663f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                    (data_end < (pMemRanges[i].offset + pMemRanges[i].size))) {
9664c7ee6f2fe100c1aacfaa0872832717c906bb8a4aMark Lobodzinski                    skip |=
9665f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
9666315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                HandleToUint64(pMemRanges[i].memory), __LINE__, VALIDATION_ERROR_0c20055a, "MEM",
9667f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                "%s: Flush/Invalidate size or offset (" PRINTF_SIZE_T_SPECIFIER ", " PRINTF_SIZE_T_SPECIFIER
9668f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                ") exceed the Memory Object's upper-bound "
9669f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                "(" PRINTF_SIZE_T_SPECIFIER "). %s",
9670f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                funcName, static_cast<size_t>(pMemRanges[i].offset + pMemRanges[i].size),
9671f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                                static_cast<size_t>(pMemRanges[i].offset), static_cast<size_t>(data_end),
9672315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                validation_error_map[VALIDATION_ERROR_0c20055a]);
9673f0b0053ba47c1fc2ee173cfef0eaf63356cd4b0cMark Lobodzinski                }
96745b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
96755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
96765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9677c7ee6f2fe100c1aacfaa0872832717c906bb8a4aMark Lobodzinski    return skip;
96785b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
96795b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9680bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinskistatic bool ValidateAndCopyNoncoherentMemoryToDriver(layer_data *dev_data, uint32_t mem_range_count,
9681bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                                     const VkMappedMemoryRange *mem_ranges) {
9682bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski    bool skip = false;
9683bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski    for (uint32_t i = 0; i < mem_range_count; ++i) {
96849a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto mem_info = GetMemObjInfo(dev_data, mem_ranges[i].memory);
968557fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        if (mem_info) {
96865f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            if (mem_info->shadow_copy) {
96875f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                VkDeviceSize size = (mem_info->mem_range.size != VK_WHOLE_SIZE)
96885f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                        ? mem_info->mem_range.size
9689d8a53ade6b5501256798a8b4ec0bc14f72adc1faTobin Ehlis                                        : (mem_info->alloc_info.allocationSize - mem_info->mem_range.offset);
96905f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                char *data = static_cast<char *>(mem_info->shadow_copy);
96915f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                for (uint64_t j = 0; j < mem_info->shadow_pad_size; ++j) {
96925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    if (data[j] != NoncoherentMemoryFillValue) {
96939b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        skip |= log_msg(
96949b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
96959b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(mem_ranges[i].memory), __LINE__, MEMTRACK_INVALID_MAP, "MEM",
96969b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "Memory underflow was detected on mem obj 0x%" PRIxLEAST64, HandleToUint64(mem_ranges[i].memory));
96975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
96985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
96995f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                for (uint64_t j = (size + mem_info->shadow_pad_size); j < (2 * mem_info->shadow_pad_size + size); ++j) {
97005b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    if (data[j] != NoncoherentMemoryFillValue) {
97019b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        skip |= log_msg(
97029b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
97039b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(mem_ranges[i].memory), __LINE__, MEMTRACK_INVALID_MAP, "MEM",
97049b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "Memory overflow was detected on mem obj 0x%" PRIxLEAST64, HandleToUint64(mem_ranges[i].memory));
97055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
97065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
97075f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                memcpy(mem_info->p_driver_data, static_cast<void *>(data + mem_info->shadow_pad_size), (size_t)(size));
97085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
97095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
97105b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
9711bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski    return skip;
97125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
97135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9714bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinskistatic void CopyNoncoherentMemoryFromDriver(layer_data *dev_data, uint32_t mem_range_count, const VkMappedMemoryRange *mem_ranges) {
9715bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski    for (uint32_t i = 0; i < mem_range_count; ++i) {
97169a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto mem_info = GetMemObjInfo(dev_data, mem_ranges[i].memory);
97175f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski        if (mem_info && mem_info->shadow_copy) {
97185f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            VkDeviceSize size = (mem_info->mem_range.size != VK_WHOLE_SIZE)
97195f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                    ? mem_info->mem_range.size
97205f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski                                    : (mem_info->alloc_info.allocationSize - mem_ranges[i].offset);
97215f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            char *data = static_cast<char *>(mem_info->shadow_copy);
97225f06b9eba1bf89d4066ca44120dcb72c4cf44104Mark Lobodzinski            memcpy(data + mem_info->shadow_pad_size, mem_info->p_driver_data, (size_t)(size));
97239e21e56fc23ade48efd3752d2e2729895eb90349Mark Lobodzinski        }
97249e21e56fc23ade48efd3752d2e2729895eb90349Mark Lobodzinski    }
97259e21e56fc23ade48efd3752d2e2729895eb90349Mark Lobodzinski}
97269e21e56fc23ade48efd3752d2e2729895eb90349Mark Lobodzinski
9727ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinskistatic bool ValidateMappedMemoryRangeDeviceLimits(layer_data *dev_data, const char *func_name, uint32_t mem_range_count,
9728ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                                                  const VkMappedMemoryRange *mem_ranges) {
9729ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski    bool skip = false;
9730ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski    for (uint32_t i = 0; i < mem_range_count; ++i) {
9731ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski        uint64_t atom_size = dev_data->phys_dev_properties.properties.limits.nonCoherentAtomSize;
973216769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton        if (SafeModulo(mem_ranges[i].offset, atom_size) != 0) {
9733df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
9734315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(mem_ranges->memory), __LINE__, VALIDATION_ERROR_0c20055e, "MEM",
9735ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            "%s: Offset in pMemRanges[%d] is 0x%" PRIxLEAST64
9736ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            ", which is not a multiple of VkPhysicalDeviceLimits::nonCoherentAtomSize (0x%" PRIxLEAST64 "). %s",
9737315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            func_name, i, mem_ranges[i].offset, atom_size, validation_error_map[VALIDATION_ERROR_0c20055e]);
9738ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski        }
973916769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton        if ((mem_ranges[i].size != VK_WHOLE_SIZE) && (SafeModulo(mem_ranges[i].size, atom_size) != 0)) {
9740df7c947594a31bb74004ab2ca335ece9b60721b6Mark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
9741315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(mem_ranges->memory), __LINE__, VALIDATION_ERROR_0c200560, "MEM",
9742ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            "%s: Size in pMemRanges[%d] is 0x%" PRIxLEAST64
9743ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski                            ", which is not a multiple of VkPhysicalDeviceLimits::nonCoherentAtomSize (0x%" PRIxLEAST64 "). %s",
9744315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            func_name, i, mem_ranges[i].size, atom_size, validation_error_map[VALIDATION_ERROR_0c200560]);
9745ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski        }
9746ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski    }
9747ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski    return skip;
9748ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski}
9749ba16c7616eb49c78dc76eb7682d650287ad8614dMark Lobodzinski
975080e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinskistatic bool PreCallValidateFlushMappedMemoryRanges(layer_data *dev_data, uint32_t mem_range_count,
975180e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski                                                   const VkMappedMemoryRange *mem_ranges) {
975280e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    bool skip = false;
975380e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    std::lock_guard<std::mutex> lock(global_lock);
975480e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    skip |= ValidateAndCopyNoncoherentMemoryToDriver(dev_data, mem_range_count, mem_ranges);
975580e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    skip |= validateMemoryIsMapped(dev_data, "vkFlushMappedMemoryRanges", mem_range_count, mem_ranges);
975680e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    return skip;
975780e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski}
975880e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski
9759bba0de708d942e9a2187158915856995db1c5a4dMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL FlushMappedMemoryRanges(VkDevice device, uint32_t memRangeCount,
9760bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                                       const VkMappedMemoryRange *pMemRanges) {
97615b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
976256e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
97635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
976480e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    if (!PreCallValidateFlushMappedMemoryRanges(dev_data, memRangeCount, pMemRanges)) {
97654a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.FlushMappedMemoryRanges(device, memRangeCount, pMemRanges);
97665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
97675b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
97685b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
97695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
977080e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinskistatic bool PreCallValidateInvalidateMappedMemoryRanges(layer_data *dev_data, uint32_t mem_range_count,
977180e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski                                                        const VkMappedMemoryRange *mem_ranges) {
977280e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    bool skip = false;
977380e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    std::lock_guard<std::mutex> lock(global_lock);
977480e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    skip |= validateMemoryIsMapped(dev_data, "vkInvalidateMappedMemoryRanges", mem_range_count, mem_ranges);
977580e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    return skip;
977680e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski}
977780e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski
977880e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinskistatic void PostCallRecordInvalidateMappedMemoryRanges(layer_data *dev_data, uint32_t mem_range_count,
977980e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski                                                       const VkMappedMemoryRange *mem_ranges) {
978080e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    std::lock_guard<std::mutex> lock(global_lock);
978180e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    // Update our shadow copy with modified driver data
978280e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    CopyNoncoherentMemoryFromDriver(dev_data, mem_range_count, mem_ranges);
978380e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski}
978480e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski
9785bba0de708d942e9a2187158915856995db1c5a4dMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL InvalidateMappedMemoryRanges(VkDevice device, uint32_t memRangeCount,
9786bba0de708d942e9a2187158915856995db1c5a4dMark Lobodzinski                                                            const VkMappedMemoryRange *pMemRanges) {
97875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
978856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
97895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
979080e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski    if (!PreCallValidateInvalidateMappedMemoryRanges(dev_data, memRangeCount, pMemRanges)) {
97914a0754042cf090e131e9e769d8a3633c228625beChris Forbes        result = dev_data->dispatch_table.InvalidateMappedMemoryRanges(device, memRangeCount, pMemRanges);
979280e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski        if (result == VK_SUCCESS) {
979380e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski            PostCallRecordInvalidateMappedMemoryRanges(dev_data, memRangeCount, pMemRanges);
979480e8617d44ad5727efb3da174951080b54b21cd8Mark Lobodzinski        }
97955b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
97965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
97975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
97985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9799160335c453ec51cc48bdef78e8befdb3c86ff292Cort Strattonstatic bool PreCallValidateBindImageMemory(layer_data *dev_data, VkImage image, IMAGE_STATE *image_state, VkDeviceMemory mem,
9800160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                                           VkDeviceSize memoryOffset) {
98010109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski    bool skip = false;
98021facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis    if (image_state) {
9803160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        std::unique_lock<std::mutex> lock(global_lock);
980494c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis        // Track objects tied to memory
98059b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus        uint64_t image_handle = HandleToUint64(image);
98067a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        skip = ValidateSetMemBinding(dev_data, mem, image_handle, kVulkanObjectTypeImage, "vkBindImageMemory()");
9807ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis        if (!image_state->memory_requirements_checked) {
9808ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            // There's not an explicit requirement in the spec to call vkGetImageMemoryRequirements() prior to calling
9809341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton            // BindImageMemory but it's implied in that memory being bound must conform with VkMemoryRequirements from
9810341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton            // vkGetImageMemoryRequirements()
98110109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
98120109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski                            image_handle, __LINE__, DRAWSTATE_INVALID_IMAGE, "DS",
98130109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski                            "vkBindImageMemory(): Binding memory to image 0x%" PRIxLEAST64
98140109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski                            " but vkGetImageMemoryRequirements() has not been called on that image.",
98150109928beb33325a442d7e3e7f38e73edf9cc38bMark Lobodzinski                            image_handle);
9816ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            // Make the call for them so we can verify the state
9817ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            lock.unlock();
9818341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton            dev_data->dispatch_table.GetImageMemoryRequirements(dev_data->device, image, &image_state->requirements);
9819ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis            lock.lock();
9820ff3ef1181960319d2268e82dae075726f650c553Tobin Ehlis        }
982147aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
98220ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        // Validate bound memory range information
98239a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto mem_info = GetMemObjInfo(dev_data, mem);
982457fc8e28c2e16118f9827e3ae1b107a27e0451a2Tobin Ehlis        if (mem_info) {
98250ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton            skip |= ValidateInsertImageMemoryRange(dev_data, image, mem_info, memoryOffset, image_state->requirements,
98260ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                                   image_state->createInfo.tiling == VK_IMAGE_TILING_LINEAR, "vkBindImageMemory()");
982774300755ed9ec780d6073af71e47f201217008d6Cort Stratton            skip |= ValidateMemoryTypes(dev_data, mem_info, image_state->requirements.memoryTypeBits, "vkBindImageMemory()",
9828315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                        VALIDATION_ERROR_1740082e);
982947aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski        }
9830160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton
9831160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        // Validate memory requirements alignment
983216769f6b2a7721e391952a97f010cbb530e4f211Dave Houlton        if (SafeModulo(memoryOffset, image_state->requirements.alignment) != 0) {
9833160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
9834315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            image_handle, __LINE__, VALIDATION_ERROR_17400830, "DS",
9835160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            "vkBindImageMemory(): memoryOffset is 0x%" PRIxLEAST64
9836160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            " but must be an integer multiple of the "
9837160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            "VkMemoryRequirements::alignment value 0x%" PRIxLEAST64
9838160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            ", returned from a call to vkGetImageMemoryRequirements with image. %s",
9839315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            memoryOffset, image_state->requirements.alignment, validation_error_map[VALIDATION_ERROR_17400830]);
9840160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        }
9841160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton
9842160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        // Validate memory requirements size
9843160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        if (image_state->requirements.size > mem_info->alloc_info.allocationSize - memoryOffset) {
9844160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
9845315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            image_handle, __LINE__, VALIDATION_ERROR_17400832, "DS",
9846160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            "vkBindImageMemory(): memory size minus memoryOffset is 0x%" PRIxLEAST64
9847160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            " but must be at least as large as "
9848160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            "VkMemoryRequirements::size value 0x%" PRIxLEAST64
9849160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            ", returned from a call to vkGetImageMemoryRequirements with image. %s",
9850160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                            mem_info->alloc_info.allocationSize - memoryOffset, image_state->requirements.size,
9851315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            validation_error_map[VALIDATION_ERROR_17400832]);
9852160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        }
9853341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    }
9854341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    return skip;
9855341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton}
985647aaf733d7394bda75c6de24289efe6b281e3cffMark Lobodzinski
9857160335c453ec51cc48bdef78e8befdb3c86ff292Cort Strattonstatic void PostCallRecordBindImageMemory(layer_data *dev_data, VkImage image, IMAGE_STATE *image_state, VkDeviceMemory mem,
9858160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton                                          VkDeviceSize memoryOffset) {
9859341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    if (image_state) {
9860160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton        std::unique_lock<std::mutex> lock(global_lock);
98610ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        // Track bound memory range information
98620ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        auto mem_info = GetMemObjInfo(dev_data, mem);
98630ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        if (mem_info) {
98640ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton            InsertImageMemoryRange(dev_data, image, mem_info, memoryOffset, image_state->requirements,
98650ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton                                   image_state->createInfo.tiling == VK_IMAGE_TILING_LINEAR);
98660ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton        }
98670ee7762cdcbfd554dd6a71c5ea48eec5e2a4a213Cort Stratton
9868c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton        // Track objects tied to memory
98699b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus        uint64_t image_handle = HandleToUint64(image);
98707a9423788398dbeb6d1fe0354a66123b61afda96Mark Lobodzinski        SetMemBinding(dev_data, mem, image_handle, kVulkanObjectTypeImage, "vkBindImageMemory()");
9871c18f059542c30f6b37f8a654df020be38adfade6Cort Stratton
9872341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton        image_state->binding.mem = mem;
9873341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton        image_state->binding.offset = memoryOffset;
9874341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton        image_state->binding.size = image_state->requirements.size;
9875341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    }
9876341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton}
9877341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton
9878341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort StrattonVKAPI_ATTR VkResult VKAPI_CALL BindImageMemory(VkDevice device, VkImage image, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
9879341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
9880341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
9881160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton    auto image_state = GetImageState(dev_data, image);
9882160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton    bool skip = PreCallValidateBindImageMemory(dev_data, image, image_state, mem, memoryOffset);
9883341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton    if (!skip) {
9884341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton        result = dev_data->dispatch_table.BindImageMemory(device, image, mem, memoryOffset);
9885341d357dc354e888bfdc05b5dfd8c1cabe8417e0Cort Stratton        if (result == VK_SUCCESS) {
9886160335c453ec51cc48bdef78e8befdb3c86ff292Cort Stratton            PostCallRecordBindImageMemory(dev_data, image, image_state, mem, memoryOffset);
988794c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis        }
98885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
98895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
98905b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
98915b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
989289d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL SetEvent(VkDevice device, VkEvent event) {
98933251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
98943ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
989556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
9896b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
98979a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto event_state = GetEventNode(dev_data, event);
98984710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis    if (event_state) {
98994710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        event_state->needsSignaled = false;
99004710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        event_state->stageMask = VK_PIPELINE_STAGE_HOST_BIT;
99014710dda89a1dd2e023334d4eda710a394b211cdcTobin Ehlis        if (event_state->write_in_use) {
99023251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT,
99039b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(event), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
99043251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Cannot call vkSetEvent() on event 0x%" PRIxLEAST64 " that is already in use by a command buffer.",
99059b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(event));
99063ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis        }
99073ee1d6057ee6c49b9dbbeb067b7fd149bdba7b5cTobin Ehlis    }
9908b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
99096fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    // Host setting event is visible to all queues immediately so update stageMask for any queue that's seen this event
99106fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    // TODO : For correctness this needs separate fix to verify that app doesn't make incorrect assumptions about the
99116fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    // ordering of this command in relation to vkCmd[Set|Reset]Events (see GH297)
99126fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    for (auto queue_data : dev_data->queueMap) {
99136fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis        auto event_entry = queue_data.second.eventToStageMap.find(event);
99146fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis        if (event_entry != queue_data.second.eventToStageMap.end()) {
99156fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis            event_entry->second |= VK_PIPELINE_STAGE_HOST_BIT;
99166fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis        }
99176fcff21b8cce5159fdfa317e612f75f5ea6a189eTobin Ehlis    }
99183251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) result = dev_data->dispatch_table.SetEvent(device, event);
99195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
99205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
99215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
9922bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL QueueBindSparse(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo *pBindInfo,
9923bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                               VkFence fence) {
992456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
99255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
99263251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
9927b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
99289a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pFence = GetFenceNode(dev_data, fence);
99299a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pQueue = GetQueueState(dev_data, queue);
9930651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
99314b38d3aa8b6be6a7f5bebb472ab439da0562824fTobin Ehlis    // First verify that fence is not in use
99323251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    skip |= ValidateFenceForSubmit(dev_data, pFence);
9933651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
99349867daedbf52debc77d6568162ee21e071699b80Chris Forbes    if (pFence) {
993593ccd9708dad3ffb58a3fc09a3d61cc5fe1569f8Mark Lobodzinski        SubmitFence(pQueue, pFence, std::max(1u, bindInfoCount));
99364b38d3aa8b6be6a7f5bebb472ab439da0562824fTobin Ehlis    }
9937651d92815dfff917308137bb67aacccc4f60df86Chris Forbes
99381344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis    for (uint32_t bindIdx = 0; bindIdx < bindInfoCount; ++bindIdx) {
99391344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        const VkBindSparseInfo &bindInfo = pBindInfo[bindIdx];
99405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // Track objects tied to memory
99411344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t j = 0; j < bindInfo.bufferBindCount; j++) {
99421344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis            for (uint32_t k = 0; k < bindInfo.pBufferBinds[j].bindCount; k++) {
9943f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                auto sparse_binding = bindInfo.pBufferBinds[j].pBinds[k];
9944f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                if (SetSparseMemBinding(dev_data, {sparse_binding.memory, sparse_binding.memoryOffset, sparse_binding.size},
99459b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                        HandleToUint64(bindInfo.pBufferBinds[j].buffer), kVulkanObjectTypeBuffer))
99463251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip = true;
99475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
99485b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
99491344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t j = 0; j < bindInfo.imageOpaqueBindCount; j++) {
99501344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis            for (uint32_t k = 0; k < bindInfo.pImageOpaqueBinds[j].bindCount; k++) {
9951f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                auto sparse_binding = bindInfo.pImageOpaqueBinds[j].pBinds[k];
9952f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                if (SetSparseMemBinding(dev_data, {sparse_binding.memory, sparse_binding.memoryOffset, sparse_binding.size},
99539b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                        HandleToUint64(bindInfo.pImageOpaqueBinds[j].image), kVulkanObjectTypeImage))
99543251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip = true;
99555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
99565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
99571344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t j = 0; j < bindInfo.imageBindCount; j++) {
99581344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis            for (uint32_t k = 0; k < bindInfo.pImageBinds[j].bindCount; k++) {
9959f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                auto sparse_binding = bindInfo.pImageBinds[j].pBinds[k];
9960f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                // TODO: This size is broken for non-opaque bindings, need to update to comprehend full sparse binding data
9961f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                VkDeviceSize size = sparse_binding.extent.depth * sparse_binding.extent.height * sparse_binding.extent.width * 4;
9962f19cf73769d6fc784ef4c3bf70b85739b4810693Tobin Ehlis                if (SetSparseMemBinding(dev_data, {sparse_binding.memory, sparse_binding.memoryOffset, size},
99639b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                        HandleToUint64(bindInfo.pImageBinds[j].image), kVulkanObjectTypeImage))
99643251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip = true;
99655b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
99665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
99679867daedbf52debc77d6568162ee21e071699b80Chris Forbes
99689867daedbf52debc77d6568162ee21e071699b80Chris Forbes        std::vector<SEMAPHORE_WAIT> semaphore_waits;
99699867daedbf52debc77d6568162ee21e071699b80Chris Forbes        std::vector<VkSemaphore> semaphore_signals;
99701344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t i = 0; i < bindInfo.waitSemaphoreCount; ++i) {
997101a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            VkSemaphore semaphore = bindInfo.pWaitSemaphores[i];
99729a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
997301a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            if (pSemaphore) {
997401a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes                if (pSemaphore->signaled) {
99759867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    if (pSemaphore->signaler.first != VK_NULL_HANDLE) {
99769867daedbf52debc77d6568162ee21e071699b80Chris Forbes                        semaphore_waits.push_back({semaphore, pSemaphore->signaler.first, pSemaphore->signaler.second});
99779867daedbf52debc77d6568162ee21e071699b80Chris Forbes                        pSemaphore->in_use.fetch_add(1);
99789867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    }
99799867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->signaler.first = VK_NULL_HANDLE;
998001a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes                    pSemaphore->signaled = false;
99811344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis                } else {
99823251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
99839b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    HandleToUint64(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
99843251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "vkQueueBindSparse: Queue 0x%p is waiting on semaphore 0x%" PRIx64
99853251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    " that has no way to be signaled.",
99869b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    queue, HandleToUint64(semaphore));
99875b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
99885b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
99895b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
99901344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        for (uint32_t i = 0; i < bindInfo.signalSemaphoreCount; ++i) {
999101a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            VkSemaphore semaphore = bindInfo.pSignalSemaphores[i];
99929a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
999301a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes            if (pSemaphore) {
999401a48e41895b3951b297ff4245eff8f9c129ae20Chris Forbes                if (pSemaphore->signaled) {
99953251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
99969b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                   HandleToUint64(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
99973251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                   "vkQueueBindSparse: Queue 0x%p is signaling semaphore 0x%" PRIx64
99983251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                   ", but that semaphore is already signaled.",
99999b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                   queue, HandleToUint64(semaphore));
10000bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                } else {
100019867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->signaler.first = queue;
100029867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->signaler.second = pQueue->seq + pQueue->submissions.size() + 1;
100039867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->signaled = true;
100049867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    pSemaphore->in_use.fetch_add(1);
100059867daedbf52debc77d6568162ee21e071699b80Chris Forbes                    semaphore_signals.push_back(semaphore);
100069867daedbf52debc77d6568162ee21e071699b80Chris Forbes                }
100075b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
100085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
100099867daedbf52debc77d6568162ee21e071699b80Chris Forbes
10010bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pQueue->submissions.emplace_back(std::vector<VkCommandBuffer>(), semaphore_waits, semaphore_signals,
100119867daedbf52debc77d6568162ee21e071699b80Chris Forbes                                         bindIdx == bindInfoCount - 1 ? fence : VK_NULL_HANDLE);
100125b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
100139867daedbf52debc77d6568162ee21e071699b80Chris Forbes
100149867daedbf52debc77d6568162ee21e071699b80Chris Forbes    if (pFence && !bindInfoCount) {
100159867daedbf52debc77d6568162ee21e071699b80Chris Forbes        // No work to do, just dropping a fence in the queue by itself.
10016bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        pQueue->submissions.emplace_back(std::vector<VkCommandBuffer>(), std::vector<SEMAPHORE_WAIT>(), std::vector<VkSemaphore>(),
100179867daedbf52debc77d6568162ee21e071699b80Chris Forbes                                         fence);
100189867daedbf52debc77d6568162ee21e071699b80Chris Forbes    }
100199867daedbf52debc77d6568162ee21e071699b80Chris Forbes
10020b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
100215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
100223251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) return dev_data->dispatch_table.QueueBindSparse(queue, bindInfoCount, pBindInfo, fence);
100235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
100245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
100255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
100265b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1002789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL CreateSemaphore(VkDevice device, const VkSemaphoreCreateInfo *pCreateInfo,
1002889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                               const VkAllocationCallbacks *pAllocator, VkSemaphore *pSemaphore) {
1002956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
100304a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateSemaphore(device, pCreateInfo, pAllocator, pSemaphore);
100315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
10032b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
10033bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        SEMAPHORE_NODE *sNode = &dev_data->semaphoreMap[*pSemaphore];
100349867daedbf52debc77d6568162ee21e071699b80Chris Forbes        sNode->signaler.first = VK_NULL_HANDLE;
100359867daedbf52debc77d6568162ee21e071699b80Chris Forbes        sNode->signaler.second = 0;
100361344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis        sNode->signaled = false;
100375b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
100385b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
100395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
100405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10041bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateEvent(VkDevice device, const VkEventCreateInfo *pCreateInfo,
10042bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                           const VkAllocationCallbacks *pAllocator, VkEvent *pEvent) {
1004356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
100444a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.CreateEvent(device, pCreateInfo, pAllocator, pEvent);
100455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (result == VK_SUCCESS) {
10046b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
100475b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->eventMap[*pEvent].needsSignaled = false;
10048293ecfc5e69ed3978a8c04518166d828294870a4Tony Barbour        dev_data->eventMap[*pEvent].write_in_use = 0;
100495b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        dev_data->eventMap[*pEvent].stageMask = VkPipelineStageFlags(0);
100505b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
100515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
100525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
100535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
100549ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinskistatic bool PreCallValidateCreateSwapchainKHR(layer_data *dev_data, const char *func_name,
100559ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                                              VkSwapchainCreateInfoKHR const *pCreateInfo, SURFACE_STATE *surface_state,
100569ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                                              SWAPCHAIN_NODE *old_swapchain_state) {
10057d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    auto most_recent_swapchain = surface_state->swapchain ? surface_state->swapchain : surface_state->old_swapchain;
10058d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes
100594bd5f453535de3d3423ff1f9995b4acb15f791d2Chris Forbes    // TODO: revisit this. some of these rules are being relaxed.
100600bbc015828bdb99e85e6731ce92428557902701fPetr Kraus
100610bbc015828bdb99e85e6731ce92428557902701fPetr Kraus    // All physical devices and queue families are required to be able
100620bbc015828bdb99e85e6731ce92428557902701fPetr Kraus    // to present to any native window on Android; require the
100630bbc015828bdb99e85e6731ce92428557902701fPetr Kraus    // application to have established support on any other platform.
10064d4eaca34eca7f4b4e34190c441a579347bb2016aMark Lobodzinski    if (!dev_data->instance_data->extensions.vk_khr_android_surface) {
100650bbc015828bdb99e85e6731ce92428557902701fPetr Kraus        auto support_predicate = [dev_data](decltype(surface_state->gpu_queue_support)::const_reference qs) -> bool {
100660bbc015828bdb99e85e6731ce92428557902701fPetr Kraus            // TODO: should restrict search only to queue families of VkDeviceQueueCreateInfos, not whole phys. device
100670bbc015828bdb99e85e6731ce92428557902701fPetr Kraus            return (qs.first.gpu == dev_data->physical_device) && qs.second;
100680bbc015828bdb99e85e6731ce92428557902701fPetr Kraus        };
100690bbc015828bdb99e85e6731ce92428557902701fPetr Kraus        const auto& support = surface_state->gpu_queue_support;
100700bbc015828bdb99e85e6731ce92428557902701fPetr Kraus        bool is_supported = std::any_of(support.begin(), support.end(), support_predicate);
100710bbc015828bdb99e85e6731ce92428557902701fPetr Kraus
100720bbc015828bdb99e85e6731ce92428557902701fPetr Kraus        if (!is_supported) {
100730bbc015828bdb99e85e6731ce92428557902701fPetr Kraus            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
10074315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_146009ec, "DS",
100750bbc015828bdb99e85e6731ce92428557902701fPetr Kraus                        "%s: pCreateInfo->surface is not known at this time to be supported for presentation by this device. "
100760bbc015828bdb99e85e6731ce92428557902701fPetr Kraus                        "The vkGetPhysicalDeviceSurfaceSupportKHR() must be called beforehand, and it must return VK_TRUE support "
100770bbc015828bdb99e85e6731ce92428557902701fPetr Kraus                        "with this surface for at least one queue family of this device. %s",
10078315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        func_name, validation_error_map[VALIDATION_ERROR_146009ec]))
100790bbc015828bdb99e85e6731ce92428557902701fPetr Kraus                return true;
100800bbc015828bdb99e85e6731ce92428557902701fPetr Kraus        }
100810bbc015828bdb99e85e6731ce92428557902701fPetr Kraus    }
100820bbc015828bdb99e85e6731ce92428557902701fPetr Kraus
10083d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    if (most_recent_swapchain != old_swapchain_state || (surface_state->old_swapchain && surface_state->swapchain)) {
10084d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
100859b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    HandleToUint64(dev_data->device), __LINE__, DRAWSTATE_SWAPCHAIN_ALREADY_EXISTS, "DS",
100869ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    "%s: surface has an existing swapchain other than oldSwapchain", func_name))
10087d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes            return true;
10088d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    }
10089d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    if (old_swapchain_state && old_swapchain_state->createInfo.surface != pCreateInfo->surface) {
10090d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
100919b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    HandleToUint64(pCreateInfo->oldSwapchain), __LINE__, DRAWSTATE_SWAPCHAIN_WRONG_SURFACE, "DS",
100929b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    "%s: pCreateInfo->oldSwapchain's surface is not pCreateInfo->surface", func_name))
10093d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes            return true;
10094d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    }
100959a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(dev_data->instance_data, dev_data->physical_device);
100967de258f87ca1192db116a66b209253793d276ebcChris Forbes    if (physical_device_state->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState == UNCALLED) {
100977de258f87ca1192db116a66b209253793d276ebcChris Forbes        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
100989b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    HandleToUint64(dev_data->physical_device), __LINE__, DRAWSTATE_SWAPCHAIN_CREATE_BEFORE_QUERY, "DS",
100999ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    "%s: surface capabilities not retrieved for this physical device", func_name))
101007de258f87ca1192db116a66b209253793d276ebcChris Forbes            return true;
10101cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    } else {  // have valid capabilities
101025c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        auto &capabilities = physical_device_state->surfaceCapabilities;
101039ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->minImageCount against VkSurfaceCapabilitiesKHR::{min|max}ImageCount:
101042fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen        if (pCreateInfo->minImageCount < capabilities.minImageCount) {
101052fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
10106315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_146009ee, "DS",
101079ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with minImageCount = %d, which is outside the bounds returned "
101082fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        "by vkGetPhysicalDeviceSurfaceCapabilitiesKHR() (i.e. minImageCount = %d, maxImageCount = %d). %s",
101099ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->minImageCount, capabilities.minImageCount, capabilities.maxImageCount,
10110315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_146009ee]))
101112fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                return true;
101122fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen        }
101132fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen
101142fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen        if ((capabilities.maxImageCount > 0) && (pCreateInfo->minImageCount > capabilities.maxImageCount)) {
101155c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
10116315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_146009f0, "DS",
101179ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with minImageCount = %d, which is outside the bounds returned "
101182fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                        "by vkGetPhysicalDeviceSurfaceCapabilitiesKHR() (i.e. minImageCount = %d, maxImageCount = %d). %s",
101199ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->minImageCount, capabilities.minImageCount, capabilities.maxImageCount,
10120315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_146009f0]))
101215c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
101225c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
101232fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen
101249ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->imageExtent against VkSurfaceCapabilitiesKHR::{current|min|max}ImageExtent:
101252e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill        if ((capabilities.currentExtent.width == kSurfaceSizeFromSwapchain) &&
101262e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill            ((pCreateInfo->imageExtent.width < capabilities.minImageExtent.width) ||
101272e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill             (pCreateInfo->imageExtent.width > capabilities.maxImageExtent.width) ||
101282e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill             (pCreateInfo->imageExtent.height < capabilities.minImageExtent.height) ||
101292e935bbc6cacaff38c073f86594a1b56d1f8a800Jamie Madill             (pCreateInfo->imageExtent.height > capabilities.maxImageExtent.height))) {
101305c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
10131315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_146009f4, "DS",
101329ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with imageExtent = (%d,%d), which is outside the bounds returned by "
101339ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "vkGetPhysicalDeviceSurfaceCapabilitiesKHR(): currentExtent = (%d,%d), minImageExtent = (%d,%d), "
101349ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "maxImageExtent = (%d,%d). %s",
101359ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->imageExtent.width, pCreateInfo->imageExtent.height,
101369ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        capabilities.currentExtent.width, capabilities.currentExtent.height, capabilities.minImageExtent.width,
101379ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        capabilities.minImageExtent.height, capabilities.maxImageExtent.width, capabilities.maxImageExtent.height,
10138315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_146009f4]))
101395c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
101405c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
101419ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // pCreateInfo->preTransform should have exactly one bit set, and that bit must also be set in
101429ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // VkSurfaceCapabilitiesKHR::supportedTransforms.
101435c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        if (!pCreateInfo->preTransform || (pCreateInfo->preTransform & (pCreateInfo->preTransform - 1)) ||
101445c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            !(pCreateInfo->preTransform & capabilities.supportedTransforms)) {
101459ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            // This is an error situation; one for which we'd like to give the developer a helpful, multi-line error message.  Build
101469ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            // it up a little at a time, and then log it:
101475c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            std::string errorString = "";
101485c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            char str[1024];
101495c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            // Here's the first part of the message:
101509ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            sprintf(str, "%s called with a non-supported pCreateInfo->preTransform (i.e. %s).  Supported values are:\n", func_name,
101515c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    string_VkSurfaceTransformFlagBitsKHR(pCreateInfo->preTransform));
101525c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            errorString += str;
101535c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            for (int i = 0; i < 32; i++) {
101545c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                // Build up the rest of the message:
101555c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                if ((1 << i) & capabilities.supportedTransforms) {
101565c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    const char *newStr = string_VkSurfaceTransformFlagBitsKHR((VkSurfaceTransformFlagBitsKHR)(1 << i));
101575c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    sprintf(str, "    %s\n", newStr);
101585c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    errorString += str;
101595c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                }
101605c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            }
101615c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            // Log the message that we've built up:
101625c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
10163315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_146009fe, "DS", "%s. %s", errorString.c_str(),
10164315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_146009fe]))
101655c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
101665c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
101677b0d28d116977b91892f354e002edd760bdb86cbChris Forbes
101689ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // pCreateInfo->compositeAlpha should have exactly one bit set, and that bit must also be set in
101699ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // VkSurfaceCapabilitiesKHR::supportedCompositeAlpha
101705c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        if (!pCreateInfo->compositeAlpha || (pCreateInfo->compositeAlpha & (pCreateInfo->compositeAlpha - 1)) ||
101715c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            !((pCreateInfo->compositeAlpha) & capabilities.supportedCompositeAlpha)) {
101729ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            // This is an error situation; one for which we'd like to give the developer a helpful, multi-line error message.  Build
101739ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            // it up a little at a time, and then log it:
101745c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            std::string errorString = "";
101755c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            char str[1024];
101765c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            // Here's the first part of the message:
101779ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            sprintf(str, "%s called with a non-supported pCreateInfo->compositeAlpha (i.e. %s).  Supported values are:\n",
101789ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    func_name, string_VkCompositeAlphaFlagBitsKHR(pCreateInfo->compositeAlpha));
101795c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            errorString += str;
101805c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            for (int i = 0; i < 32; i++) {
101815c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                // Build up the rest of the message:
101825c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                if ((1 << i) & capabilities.supportedCompositeAlpha) {
101835c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    const char *newStr = string_VkCompositeAlphaFlagBitsKHR((VkCompositeAlphaFlagBitsKHR)(1 << i));
101845c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    sprintf(str, "    %s\n", newStr);
101855c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                    errorString += str;
101865c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                }
101875c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            }
101885c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            // Log the message that we've built up:
101895c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
10190315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_14600a00, "DS", "%s. %s", errorString.c_str(),
10191315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_14600a00]))
101925c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
101935c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
101949ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->imageArrayLayers against VkSurfaceCapabilitiesKHR::maxImageArrayLayers:
101955c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        if ((pCreateInfo->imageArrayLayers < 1) || (pCreateInfo->imageArrayLayers > capabilities.maxImageArrayLayers)) {
101965c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
10197315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_146009f6, "DS",
101989ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with a non-supported imageArrayLayers (i.e. %d).  Minimum value is 1, maximum value is %d. %s",
101999ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->imageArrayLayers, capabilities.maxImageArrayLayers,
10200315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_146009f6]))
102015c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
102025c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
102039ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->imageUsage against VkSurfaceCapabilitiesKHR::supportedUsageFlags:
102045c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        if (pCreateInfo->imageUsage != (pCreateInfo->imageUsage & capabilities.supportedUsageFlags)) {
102055c99b4daed164798f307244c9bde17b4f66014fbChris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
10206315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_146009f8, "DS",
102079ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with a non-supported pCreateInfo->imageUsage (i.e. 0x%08x).  Supported flag bits are 0x%08x. %s",
102089ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        func_name, pCreateInfo->imageUsage, capabilities.supportedUsageFlags,
10209315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_146009f8]))
102105c99b4daed164798f307244c9bde17b4f66014fbChris Forbes                return true;
102115c99b4daed164798f307244c9bde17b4f66014fbChris Forbes        }
102127de258f87ca1192db116a66b209253793d276ebcChris Forbes    }
10213d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes
102149ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski    // Validate pCreateInfo values with the results of vkGetPhysicalDeviceSurfaceFormatsKHR():
102155faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    if (physical_device_state->vkGetPhysicalDeviceSurfaceFormatsKHRState != QUERY_DETAILS) {
102165faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
102179b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    HandleToUint64(dev_data->device), __LINE__, DRAWSTATE_SWAPCHAIN_CREATE_BEFORE_QUERY, "DS",
102189ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                    "%s called before calling vkGetPhysicalDeviceSurfaceFormatsKHR().", func_name))
102195faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            return true;
102205faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    } else {
102219ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->imageFormat against VkSurfaceFormatKHR::format:
102225faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        bool foundFormat = false;
102235faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        bool foundColorSpace = false;
102245faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        bool foundMatch = false;
102255faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        for (auto const &format : physical_device_state->surface_formats) {
102265faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            if (pCreateInfo->imageFormat == format.format) {
102279ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                // Validate pCreateInfo->imageColorSpace against VkSurfaceFormatKHR::colorSpace:
102285faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                foundFormat = true;
102295faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                if (pCreateInfo->imageColorSpace == format.colorSpace) {
102305faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    foundMatch = true;
102315faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    break;
102325faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                }
102335faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            } else {
102345faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                if (pCreateInfo->imageColorSpace == format.colorSpace) {
102355faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    foundColorSpace = true;
102365faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                }
102375faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            }
102385faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        }
102395faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        if (!foundMatch) {
102405faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            if (!foundFormat) {
102415faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
10242315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_146009f2, "DS",
10243bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "%s called with a non-supported pCreateInfo->imageFormat (i.e. %d). %s", func_name,
10244315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            pCreateInfo->imageFormat, validation_error_map[VALIDATION_ERROR_146009f2]))
102452fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                    return true;
102462fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen            }
102472fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen            if (!foundColorSpace) {
102482fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
10249315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_146009f2, "DS",
10250bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                            "%s called with a non-supported pCreateInfo->imageColorSpace (i.e. %d). %s", func_name,
10251315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                            pCreateInfo->imageColorSpace, validation_error_map[VALIDATION_ERROR_146009f2]))
102525faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                    return true;
102535faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            }
102545faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        }
102555faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    }
102565faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
102579ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski    // Validate pCreateInfo values with the results of vkGetPhysicalDeviceSurfacePresentModesKHR():
102589e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    if (physical_device_state->vkGetPhysicalDeviceSurfacePresentModesKHRState != QUERY_DETAILS) {
1025925002b75574f762c62b1a00a595bab04ebb25452Mark Lobodzinski        // FIFO is required to always be supported
102609e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        if (pCreateInfo->presentMode != VK_PRESENT_MODE_FIFO_KHR) {
102619e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
102629b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(dev_data->device), __LINE__, DRAWSTATE_SWAPCHAIN_CREATE_BEFORE_QUERY, "DS",
102639ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called before calling vkGetPhysicalDeviceSurfacePresentModesKHR().", func_name))
102649e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                return true;
102659e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
102669e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    } else {
102679ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski        // Validate pCreateInfo->presentMode against vkGetPhysicalDeviceSurfacePresentModesKHR():
10268bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        bool foundMatch = std::find(physical_device_state->present_modes.begin(), physical_device_state->present_modes.end(),
102699e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                                    pCreateInfo->presentMode) != physical_device_state->present_modes.end();
102709e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        if (!foundMatch) {
102719e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
10272315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(dev_data->device), __LINE__, VALIDATION_ERROR_14600a02, "DS",
102739ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski                        "%s called with a non-supported presentMode (i.e. %s). %s", func_name,
10274315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        string_VkPresentModeKHR(pCreateInfo->presentMode), validation_error_map[VALIDATION_ERROR_14600a02]))
102759e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                return true;
102769e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
102779e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    }
1027887a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis    // Validate state for shared presentable case
1027987a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis    if (VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR == pCreateInfo->presentMode ||
1028087a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis        VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR == pCreateInfo->presentMode) {
10281a149f1a0cb39b48b19822c8cf9ef2426cd2251dfMark Lobodzinski        if (!dev_data->extensions.vk_khr_shared_presentable_image) {
1028287a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
10283480a11822ef9a45f577f13644759c0895a49db19Tobin Ehlis                        HandleToUint64(dev_data->device), __LINE__, DRAWSTATE_EXTENSION_NOT_ENABLED, "DS",
102846084b78a58b438d27591b81efe30997ac9d88d3cMark Lobodzinski                        "%s called with presentMode %s which requires the VK_KHR_shared_presentable_image extension, which has not "
102856084b78a58b438d27591b81efe30997ac9d88d3cMark Lobodzinski                        "been enabled.",
102866084b78a58b438d27591b81efe30997ac9d88d3cMark Lobodzinski                        func_name, string_VkPresentModeKHR(pCreateInfo->presentMode)))
102876084b78a58b438d27591b81efe30997ac9d88d3cMark Lobodzinski                return true;
102886084b78a58b438d27591b81efe30997ac9d88d3cMark Lobodzinski        } else if (pCreateInfo->minImageCount != 1) {
102896084b78a58b438d27591b81efe30997ac9d88d3cMark Lobodzinski            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
10290315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        reinterpret_cast<uint64_t>(dev_data->device), __LINE__, VALIDATION_ERROR_14600ace, "DS",
1029187a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis                        "%s called with presentMode %s, but minImageCount value is %d. For shared presentable image, minImageCount "
102926084b78a58b438d27591b81efe30997ac9d88d3cMark Lobodzinski                        "must be 1. %s",
102936084b78a58b438d27591b81efe30997ac9d88d3cMark Lobodzinski                        func_name, string_VkPresentModeKHR(pCreateInfo->presentMode), pCreateInfo->minImageCount,
10294315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_14600ace]))
1029587a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis                return true;
1029687a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis        }
1029787a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis    }
102989e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
10299d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes    return false;
10300d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes}
10301d3b3114fb37a32af2ba563f784da54a877492b23Chris Forbes
10302261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinskistatic void PostCallRecordCreateSwapchainKHR(layer_data *dev_data, VkResult result, const VkSwapchainCreateInfoKHR *pCreateInfo,
10303261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski                                             VkSwapchainKHR *pSwapchain, SURFACE_STATE *surface_state,
10304261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski                                             SWAPCHAIN_NODE *old_swapchain_state) {
103055b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == result) {
10306b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
10307ddc5201048319558ce66701163a4546ee957af19Chris Forbes        auto swapchain_state = unique_ptr<SWAPCHAIN_NODE>(new SWAPCHAIN_NODE(pCreateInfo, *pSwapchain));
1030887a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis        if (VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR == pCreateInfo->presentMode ||
1030987a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis            VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR == pCreateInfo->presentMode) {
1031087a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis            swapchain_state->shared_presentable = true;
1031187a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis        }
10312ddc5201048319558ce66701163a4546ee957af19Chris Forbes        surface_state->swapchain = swapchain_state.get();
1031316a1f8f9c4af479b1873e82ff02360817fb658acChris Forbes        dev_data->swapchainMap[*pSwapchain] = std::move(swapchain_state);
10314ddc5201048319558ce66701163a4546ee957af19Chris Forbes    } else {
10315ddc5201048319558ce66701163a4546ee957af19Chris Forbes        surface_state->swapchain = nullptr;
103165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10317ddc5201048319558ce66701163a4546ee957af19Chris Forbes    // Spec requires that even if CreateSwapchainKHR fails, oldSwapchain behaves as replaced.
103185b5488456e5afa0487f95b805a2aba59b13d69f4Chris Forbes    if (old_swapchain_state) {
103195b5488456e5afa0487f95b805a2aba59b13d69f4Chris Forbes        old_swapchain_state->replaced = true;
103205b5488456e5afa0487f95b805a2aba59b13d69f4Chris Forbes    }
10321ddc5201048319558ce66701163a4546ee957af19Chris Forbes    surface_state->old_swapchain = old_swapchain_state;
10322261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski    return;
10323261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski}
10324261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski
10325261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo,
10326261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski                                                  const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchain) {
1032756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
103289a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto surface_state = GetSurfaceState(dev_data->instance_data, pCreateInfo->surface);
103299a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto old_swapchain_state = GetSwapchainNode(dev_data, pCreateInfo->oldSwapchain);
10330261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski
103319ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski    if (PreCallValidateCreateSwapchainKHR(dev_data, "vkCreateSwapChainKHR()", pCreateInfo, surface_state, old_swapchain_state)) {
10332261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski        return VK_ERROR_VALIDATION_FAILED_EXT;
10333261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski    }
10334261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski
10335261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski    VkResult result = dev_data->dispatch_table.CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain);
10336261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski
10337261dc1ef7a86b64cce92a6811bf80ee4ba364a48Mark Lobodzinski    PostCallRecordCreateSwapchainKHR(dev_data, result, pCreateInfo, pSwapchain, surface_state, old_swapchain_state);
10338ddc5201048319558ce66701163a4546ee957af19Chris Forbes
103395b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
103405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
103415b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10342bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks *pAllocator) {
1034356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
103443251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
103455b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10346b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
103479a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto swapchain_data = GetSwapchainNode(dev_data, swapchain);
10348b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis    if (swapchain_data) {
10349b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis        if (swapchain_data->images.size() > 0) {
10350b110cb87b9478586719d7f7dc769b350857366baTobin Ehlis            for (auto swapchain_image : swapchain_data->images) {
103515b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                auto image_sub = dev_data->imageSubresourceMap.find(swapchain_image);
103525b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                if (image_sub != dev_data->imageSubresourceMap.end()) {
103535b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    for (auto imgsubpair : image_sub->second) {
103545b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        auto image_item = dev_data->imageLayoutMap.find(imgsubpair);
103555b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        if (image_item != dev_data->imageLayoutMap.end()) {
103565b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                            dev_data->imageLayoutMap.erase(image_item);
103575b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                        }
103585b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
103595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    dev_data->imageSubresourceMap.erase(image_sub);
103605b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
103619b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                skip = ClearMemoryObjectBindings(dev_data, HandleToUint64(swapchain_image), kVulkanObjectTypeSwapchainKHR);
1036294c53c062f0ccc70ef0ada8e98edc90eadc4cb45Tobin Ehlis                dev_data->imageMap.erase(swapchain_image);
103635b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
103645b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
10365ddc5201048319558ce66701163a4546ee957af19Chris Forbes
103669a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto surface_state = GetSurfaceState(dev_data->instance_data, swapchain_data->createInfo.surface);
10367ddc5201048319558ce66701163a4546ee957af19Chris Forbes        if (surface_state) {
10368cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (surface_state->swapchain == swapchain_data) surface_state->swapchain = nullptr;
10369cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (surface_state->old_swapchain == swapchain_data) surface_state->old_swapchain = nullptr;
10370ddc5201048319558ce66701163a4546ee957af19Chris Forbes        }
10371ddc5201048319558ce66701163a4546ee957af19Chris Forbes
1037216a1f8f9c4af479b1873e82ff02360817fb658acChris Forbes        dev_data->swapchainMap.erase(swapchain);
103735b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10374b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
103753251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) dev_data->dispatch_table.DestroySwapchainKHR(device, swapchain, pAllocator);
103765b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
103775b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10378bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pCount,
10379bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                     VkImage *pSwapchainImages) {
1038056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
103814a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.GetSwapchainImagesKHR(device, swapchain, pCount, pSwapchainImages);
103825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10383ee52d734440f0770b3ac5ebde5a137d2e40589deChris Forbes    if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pSwapchainImages != nullptr) {
103845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        // This should never happen and is checked by param checker.
10385cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        if (!pCount) return result;
10386b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
103879a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto swapchain_node = GetSwapchainNode(dev_data, swapchain);
10388ee52d734440f0770b3ac5ebde5a137d2e40589deChris Forbes
10389ee52d734440f0770b3ac5ebde5a137d2e40589deChris Forbes        if (*pCount > swapchain_node->images.size())
10390ee52d734440f0770b3ac5ebde5a137d2e40589deChris Forbes            swapchain_node->images.resize(*pCount);
10391ee52d734440f0770b3ac5ebde5a137d2e40589deChris Forbes
103925b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        for (uint32_t i = 0; i < *pCount; ++i) {
10393ee52d734440f0770b3ac5ebde5a137d2e40589deChris Forbes            if (swapchain_node->images[i] != VK_NULL_HANDLE)
10394ee52d734440f0770b3ac5ebde5a137d2e40589deChris Forbes                continue;   // Already retrieved this.
10395ee52d734440f0770b3ac5ebde5a137d2e40589deChris Forbes
103965b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            IMAGE_LAYOUT_NODE image_layout_node;
103975b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            image_layout_node.layout = VK_IMAGE_LAYOUT_UNDEFINED;
103985b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            image_layout_node.format = swapchain_node->createInfo.imageFormat;
103996d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            // Add imageMap entries for each swapchain image
104006d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            VkImageCreateInfo image_ci = {};
10401eb6ea7587bdc06e98a89398f113fe3610d270dcbChris Forbes            image_ci.flags = 0;
10402eb6ea7587bdc06e98a89398f113fe3610d270dcbChris Forbes            image_ci.imageType = VK_IMAGE_TYPE_2D;
104036d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.format = swapchain_node->createInfo.imageFormat;
104046d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.extent.width = swapchain_node->createInfo.imageExtent.width;
104056d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.extent.height = swapchain_node->createInfo.imageExtent.height;
10406d1a9776c1a22ec99a3ef0dd44e7f85a78a04d1edTony Barbour            image_ci.extent.depth = 1;
10407eb6ea7587bdc06e98a89398f113fe3610d270dcbChris Forbes            image_ci.mipLevels = 1;
10408eb6ea7587bdc06e98a89398f113fe3610d270dcbChris Forbes            image_ci.arrayLayers = swapchain_node->createInfo.imageArrayLayers;
10409eb6ea7587bdc06e98a89398f113fe3610d270dcbChris Forbes            image_ci.samples = VK_SAMPLE_COUNT_1_BIT;
10410eb6ea7587bdc06e98a89398f113fe3610d270dcbChris Forbes            image_ci.tiling = VK_IMAGE_TILING_OPTIMAL;
10411eb6ea7587bdc06e98a89398f113fe3610d270dcbChris Forbes            image_ci.usage = swapchain_node->createInfo.imageUsage;
104126d1373829eded68f6e080ff2c33e03231360ed57Tobin Ehlis            image_ci.sharingMode = swapchain_node->createInfo.imageSharingMode;
104131facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            dev_data->imageMap[pSwapchainImages[i]] = unique_ptr<IMAGE_STATE>(new IMAGE_STATE(pSwapchainImages[i], &image_ci));
104141facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            auto &image_state = dev_data->imageMap[pSwapchainImages[i]];
104151facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            image_state->valid = false;
10416e46491ee6f16b9d29e68914fc6522aba2fde0ad4Tobin Ehlis            image_state->binding.mem = MEMTRACKER_SWAP_CHAIN_IMAGE_KEY;
10417ee52d734440f0770b3ac5ebde5a137d2e40589deChris Forbes            swapchain_node->images[i] = pSwapchainImages[i];
104185b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            ImageSubresourcePair subpair = {pSwapchainImages[i], false, VkImageSubresource()};
104195b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->imageSubresourceMap[pSwapchainImages[i]].push_back(subpair);
104205b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            dev_data->imageLayoutMap[subpair] = image_layout_node;
104215b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
104225b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
104235b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
104245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
104255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1042689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo) {
1042756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
104283251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
104295b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
104306c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    std::lock_guard<std::mutex> lock(global_lock);
104319a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto queue_state = GetQueueState(dev_data, queue);
104321671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes
104336c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    for (uint32_t i = 0; i < pPresentInfo->waitSemaphoreCount; ++i) {
104349a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto pSemaphore = GetSemaphoreNode(dev_data, pPresentInfo->pWaitSemaphores[i]);
104356c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        if (pSemaphore && !pSemaphore->signaled) {
104363251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
104373251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
104383251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Queue 0x%p is waiting on semaphore 0x%" PRIx64 " that has no way to be signaled.", queue,
104399b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pPresentInfo->pWaitSemaphores[i]));
104405b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
104416c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    }
10442249eb117f85f5e0f3f3a83a2bf297893e0d054ceTobin Ehlis
104436c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    for (uint32_t i = 0; i < pPresentInfo->swapchainCount; ++i) {
104449a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto swapchain_data = GetSwapchainNode(dev_data, pPresentInfo->pSwapchains[i]);
10445a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes        if (swapchain_data) {
10446a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes            if (pPresentInfo->pImageIndices[i] >= swapchain_data->images.size()) {
104479b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                skip |=
104489b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
104499b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            HandleToUint64(pPresentInfo->pSwapchains[i]), __LINE__, DRAWSTATE_SWAPCHAIN_INVALID_IMAGE, "DS",
104509b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            "vkQueuePresentKHR: Swapchain image index too large (%u). There are only %u images in this swapchain.",
104519b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            pPresentInfo->pImageIndices[i], (uint32_t)swapchain_data->images.size());
10452bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            } else {
10453a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                auto image = swapchain_data->images[pPresentInfo->pImageIndices[i]];
104549a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto image_state = GetImageState(dev_data, image);
1045587a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis
1045687a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis                if (image_state->shared_presentable) {
1045787a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis                    image_state->layout_locked = true;
1045887a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis                }
10459c4f799ed5502f05ce97543e0500b4a19dc5f2461Mark Lobodzinski
104603251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= ValidateImageMemoryIsValid(dev_data, image_state, "vkQueuePresentKHR()");
10461a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes
104621facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis                if (!image_state->acquired) {
104633251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(
10464bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
104659b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(pPresentInfo->pSwapchains[i]), __LINE__, DRAWSTATE_SWAPCHAIN_IMAGE_NOT_ACQUIRED, "DS",
10466bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                        "vkQueuePresentKHR: Swapchain image index %u has not been acquired.", pPresentInfo->pImageIndices[i]);
10467a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                }
10468a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes
10469a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                vector<VkImageLayout> layouts;
10470a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                if (FindLayouts(dev_data, image, layouts)) {
10471a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                    for (auto layout : layouts) {
104726084b78a58b438d27591b81efe30997ac9d88d3cMark Lobodzinski                        if ((layout != VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) &&
10473a149f1a0cb39b48b19822c8cf9ef2426cd2251dfMark Lobodzinski                            (!dev_data->extensions.vk_khr_shared_presentable_image ||
104746084b78a58b438d27591b81efe30997ac9d88d3cMark Lobodzinski                             (layout != VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR))) {
104753251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            skip |=
104762fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT,
10477315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                        HandleToUint64(queue), __LINE__, VALIDATION_ERROR_11200a20, "DS",
104782fbc1a61dff1781368a0c592c25985abb46e4891Mike Weiblen                                        "Images passed to present must be in layout "
104796084b78a58b438d27591b81efe30997ac9d88d3cMark Lobodzinski                                        "VK_IMAGE_LAYOUT_PRESENT_SRC_KHR or VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR but is in %s. %s",
10480315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                        string_VkImageLayout(layout), validation_error_map[VALIDATION_ERROR_11200a20]);
10481a96bccebcf27add1b38bfe46c541e1484d7b4d88Chris Forbes                        }
104825b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                    }
104835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis                }
104845b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis            }
104851671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes
104861671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            // All physical devices and queue families are required to be able
104871671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            // to present to any native window on Android; require the
104881671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            // application to have established support on any other platform.
10489d4eaca34eca7f4b4e34190c441a579347bb2016aMark Lobodzinski            if (!dev_data->instance_data->extensions.vk_khr_android_surface) {
104909a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                auto surface_state = GetSurfaceState(dev_data->instance_data, swapchain_data->createInfo.surface);
104911671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                auto support_it = surface_state->gpu_queue_support.find({dev_data->physical_device, queue_state->queueFamilyIndex});
104921671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes
104931671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                if (support_it == surface_state->gpu_queue_support.end()) {
104943251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |=
104951671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
104969b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pPresentInfo->pSwapchains[i]), __LINE__, DRAWSTATE_SWAPCHAIN_UNSUPPORTED_QUEUE, "DS",
10497cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                "vkQueuePresentKHR: Presenting image without calling "
10498cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                                "vkGetPhysicalDeviceSurfaceSupportKHR");
104991671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                } else if (!support_it->second) {
105009b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    skip |=
105019b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
10502315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                HandleToUint64(pPresentInfo->pSwapchains[i]), __LINE__, VALIDATION_ERROR_31800a18, "DS",
105039b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "vkQueuePresentKHR: Presenting image on queue that cannot "
105049b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "present to this surface. %s",
10505315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                validation_error_map[VALIDATION_ERROR_31800a18]);
105061671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes                }
105071671dfbfc53aa19dcf76d71c2dd1f8f2c4879174Chris Forbes            }
105085b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis        }
105095b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10510c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis    if (pPresentInfo && pPresentInfo->pNext) {
10511c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis        // Verify ext struct
10512c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis        struct std_header {
10513c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis            VkStructureType sType;
10514c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis            const void *pNext;
10515c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis        };
10516c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis        std_header *pnext = (std_header *)pPresentInfo->pNext;
10517c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis        while (pnext) {
10518c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis            if (VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR == pnext->sType) {
10519c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                VkPresentRegionsKHR *present_regions = (VkPresentRegionsKHR *)pnext;
10520c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                for (uint32_t i = 0; i < present_regions->swapchainCount; ++i) {
10521c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                    auto swapchain_data = GetSwapchainNode(dev_data, pPresentInfo->pSwapchains[i]);
10522c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                    assert(swapchain_data);
10523c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                    VkPresentRegionKHR region = present_regions->pRegions[i];
10524c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                    for (uint32_t j = 0; j < region.rectangleCount; ++j) {
10525c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                        VkRectLayerKHR rect = region.pRectangles[j];
10526c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                        // TODO: Need to update these errors to their unique error ids when available
10527c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                        if ((rect.offset.x + rect.extent.width) > swapchain_data->createInfo.imageExtent.width) {
105289b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            skip |= log_msg(
105299b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
105309b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pPresentInfo->pSwapchains[i]), __LINE__, DRAWSTATE_SWAPCHAIN_INVALID_IMAGE, "DS",
105319b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "vkQueuePresentKHR(): For VkPresentRegionKHR down pNext "
105329b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "chain, pRegion[%i].pRectangles[%i], the sum of offset.x "
105339b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "(%i) and extent.width (%i) is greater than the "
105349b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "corresponding swapchain's imageExtent.width (%i).",
105359b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                i, j, rect.offset.x, rect.extent.width, swapchain_data->createInfo.imageExtent.width);
10536c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                        }
10537c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                        if ((rect.offset.y + rect.extent.height) > swapchain_data->createInfo.imageExtent.height) {
105389b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                            skip |= log_msg(
105399b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
105409b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pPresentInfo->pSwapchains[i]), __LINE__, DRAWSTATE_SWAPCHAIN_INVALID_IMAGE, "DS",
105419b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "vkQueuePresentKHR(): For VkPresentRegionKHR down pNext "
105429b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "chain, pRegion[%i].pRectangles[%i], the sum of offset.y "
105439b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "(%i) and extent.height (%i) is greater than the "
105449b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                "corresponding swapchain's imageExtent.height (%i).",
105459b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                i, j, rect.offset.y, rect.extent.height, swapchain_data->createInfo.imageExtent.height);
10546c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                        }
10547c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                        if (rect.layer > swapchain_data->createInfo.imageArrayLayers) {
105483251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            skip |= log_msg(
10549c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
105509b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pPresentInfo->pSwapchains[i]), __LINE__, DRAWSTATE_SWAPCHAIN_INVALID_IMAGE, "DS",
10551c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                                "vkQueuePresentKHR(): For VkPresentRegionKHR down pNext chain, pRegion[%i].pRectangles[%i], the "
10552c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                                "layer (%i) is greater than the corresponding swapchain's imageArrayLayers (%i).",
10553c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                                i, j, rect.layer, swapchain_data->createInfo.imageArrayLayers);
10554c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                        }
10555c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                    }
10556c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis                }
105575f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis            } else if (VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE == pnext->sType) {
105585f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                VkPresentTimesInfoGOOGLE *present_times_info = (VkPresentTimesInfoGOOGLE *)pnext;
105595f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                if (pPresentInfo->swapchainCount != present_times_info->swapchainCount) {
105605f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                    skip |=
105615f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
105629b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                HandleToUint64(pPresentInfo->pSwapchains[0]), __LINE__,
105635f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis
10564315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                                VALIDATION_ERROR_118009be, "DS",
105655f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                                "vkQueuePresentKHR(): VkPresentTimesInfoGOOGLE.swapchainCount is %i but "
105665f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                                "pPresentInfo->swapchainCount is %i. For VkPresentTimesInfoGOOGLE down pNext "
105675f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                                "chain of VkPresentInfoKHR, VkPresentTimesInfoGOOGLE.swapchainCount "
105685f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                                "must equal VkPresentInfoKHR.swapchainCount.",
105695f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                                present_times_info->swapchainCount, pPresentInfo->swapchainCount);
105705f5e4095d630df9003597a928c86502e3fc83176Tobin Ehlis                }
10571c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis            }
10572c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis            pnext = (std_header *)pnext->pNext;
10573c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis        }
10574c78bb8f84551ddfb3802d18c678500e26e4116cbTobin Ehlis    }
105755b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
105763251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) {
105776c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        return VK_ERROR_VALIDATION_FAILED_EXT;
105786c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    }
105796c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes
105804a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.QueuePresentKHR(queue, pPresentInfo);
105816c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes
105826c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    if (result != VK_ERROR_VALIDATION_FAILED_EXT) {
105836c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        // Semaphore waits occur before error generation, if the call reached
105846c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        // the ICD. (Confirm?)
105856c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        for (uint32_t i = 0; i < pPresentInfo->waitSemaphoreCount; ++i) {
105869a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto pSemaphore = GetSemaphoreNode(dev_data, pPresentInfo->pWaitSemaphores[i]);
105879867daedbf52debc77d6568162ee21e071699b80Chris Forbes            if (pSemaphore) {
105889867daedbf52debc77d6568162ee21e071699b80Chris Forbes                pSemaphore->signaler.first = VK_NULL_HANDLE;
105896c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes                pSemaphore->signaled = false;
105906c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes            }
105916c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes        }
105929867daedbf52debc77d6568162ee21e071699b80Chris Forbes
10593220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes        for (uint32_t i = 0; i < pPresentInfo->swapchainCount; ++i) {
10594220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            // Note: this is imperfect, in that we can get confused about what
10595220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            // did or didn't succeed-- but if the app does that, it's confused
10596220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            // itself just as much.
10597220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            auto local_result = pPresentInfo->pResults ? pPresentInfo->pResults[i] : result;
10598220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes
10599cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (local_result != VK_SUCCESS && local_result != VK_SUBOPTIMAL_KHR) continue;  // this present didn't actually happen.
10600220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes
10601220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            // Mark the image as having been released to the WSI
106029a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto swapchain_data = GetSwapchainNode(dev_data, pPresentInfo->pSwapchains[i]);
10603220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes            auto image = swapchain_data->images[pPresentInfo->pImageIndices[i]];
106049a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            auto image_state = GetImageState(dev_data, image);
106051facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis            image_state->acquired = false;
10606220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes        }
10607220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes
106089867daedbf52debc77d6568162ee21e071699b80Chris Forbes        // Note: even though presentation is directed to a queue, there is no
106099867daedbf52debc77d6568162ee21e071699b80Chris Forbes        // direct ordering between QP and subsequent work, so QP (and its
106109867daedbf52debc77d6568162ee21e071699b80Chris Forbes        // semaphore waits) /never/ participate in any completion proof.
106116c87c6a8acda49a6406192a1b634e9bf060bd6fdChris Forbes    }
106121344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
106135b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
106145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
106155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10616c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinskistatic bool PreCallValidateCreateSharedSwapchainsKHR(layer_data *dev_data, uint32_t swapchainCount,
10617c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                     const VkSwapchainCreateInfoKHR *pCreateInfos, VkSwapchainKHR *pSwapchains,
10618c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                     std::vector<SURFACE_STATE *> &surface_state,
10619c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                     std::vector<SWAPCHAIN_NODE *> &old_swapchain_state) {
106200342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    if (pCreateInfos) {
10621c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski        std::lock_guard<std::mutex> lock(global_lock);
106220342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        for (uint32_t i = 0; i < swapchainCount; i++) {
106239a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            surface_state.push_back(GetSurfaceState(dev_data->instance_data, pCreateInfos[i].surface));
106249a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis            old_swapchain_state.push_back(GetSwapchainNode(dev_data, pCreateInfos[i].oldSwapchain));
106259ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            std::stringstream func_name;
106269ad55a294cd317a63498d79878e1d5e7d1156c91Mark Lobodzinski            func_name << "vkCreateSharedSwapchainsKHR[" << swapchainCount << "]";
10627bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski            if (PreCallValidateCreateSwapchainKHR(dev_data, func_name.str().c_str(), &pCreateInfos[i], surface_state[i],
10628bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                  old_swapchain_state[i])) {
10629c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                return true;
106300342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            }
106310342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        }
106320342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    }
10633c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    return false;
10634c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski}
106350342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski
10636c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinskistatic void PostCallRecordCreateSharedSwapchainsKHR(layer_data *dev_data, VkResult result, uint32_t swapchainCount,
10637c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                    const VkSwapchainCreateInfoKHR *pCreateInfos, VkSwapchainKHR *pSwapchains,
10638c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                    std::vector<SURFACE_STATE *> &surface_state,
10639c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                    std::vector<SWAPCHAIN_NODE *> &old_swapchain_state) {
106400342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    if (VK_SUCCESS == result) {
106410342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        for (uint32_t i = 0; i < swapchainCount; i++) {
106420342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            auto swapchain_state = unique_ptr<SWAPCHAIN_NODE>(new SWAPCHAIN_NODE(&pCreateInfos[i], pSwapchains[i]));
1064387a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis            if (VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR == pCreateInfos[i].presentMode ||
1064487a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis                VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR == pCreateInfos[i].presentMode) {
1064587a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis                swapchain_state->shared_presentable = true;
1064687a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis            }
106470342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            surface_state[i]->swapchain = swapchain_state.get();
1064816a1f8f9c4af479b1873e82ff02360817fb658acChris Forbes            dev_data->swapchainMap[pSwapchains[i]] = std::move(swapchain_state);
106490342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        }
106500342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    } else {
106510342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        for (uint32_t i = 0; i < swapchainCount; i++) {
106520342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            surface_state[i]->swapchain = nullptr;
106530342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        }
106540342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    }
106550342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    // Spec requires that even if CreateSharedSwapchainKHR fails, oldSwapchain behaves as replaced.
106560342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    for (uint32_t i = 0; i < swapchainCount; i++) {
106570342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        if (old_swapchain_state[i]) {
106580342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski            old_swapchain_state[i]->replaced = true;
106590342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        }
106600342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski        surface_state[i]->old_swapchain = old_swapchain_state[i];
106610342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski    }
10662c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    return;
10663c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski}
10664c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski
10665c6cd632d064579a64e61d8704b411d0e4ace7adaMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateSharedSwapchainsKHR(VkDevice device, uint32_t swapchainCount,
10666c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                         const VkSwapchainCreateInfoKHR *pCreateInfos,
10667c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                         const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchains) {
1066856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
10669c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    std::vector<SURFACE_STATE *> surface_state;
10670c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    std::vector<SWAPCHAIN_NODE *> old_swapchain_state;
10671c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski
10672c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    if (PreCallValidateCreateSharedSwapchainsKHR(dev_data, swapchainCount, pCreateInfos, pSwapchains, surface_state,
10673c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                                 old_swapchain_state)) {
10674c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski        return VK_ERROR_VALIDATION_FAILED_EXT;
10675c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    }
10676c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski
10677c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    VkResult result =
10678c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski        dev_data->dispatch_table.CreateSharedSwapchainsKHR(device, swapchainCount, pCreateInfos, pAllocator, pSwapchains);
10679c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski
10680c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski    PostCallRecordCreateSharedSwapchainsKHR(dev_data, result, swapchainCount, pCreateInfos, pSwapchains, surface_state,
10681c6cd632d064579a64e61d8704b411d0e4ace7adaMark Lobodzinski                                            old_swapchain_state);
106820342b03ca27e5dcd692e5161af9e0eddda80240eMark Lobodzinski
10683c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young    return result;
10684c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young}
10685c827a5880dc3fabfc7d1a58bb62798649cab1181Mark Young
1068689d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR VkResult VKAPI_CALL AcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout,
1068789d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                   VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex) {
1068856e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
106893251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
106901344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
10691b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::unique_lock<std::mutex> lock(global_lock);
10692449670637ef4214b33018f497cf10daeff9dc85bChris Forbes
10693449670637ef4214b33018f497cf10daeff9dc85bChris Forbes    if (fence == VK_NULL_HANDLE && semaphore == VK_NULL_HANDLE) {
106943251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
106959b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(device), __LINE__, DRAWSTATE_SWAPCHAIN_NO_SYNC_FOR_ACQUIRE, "DS",
106963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkAcquireNextImageKHR: Semaphore and fence cannot both be VK_NULL_HANDLE. There would be no way "
106973251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "to determine the completion of this operation.");
10698449670637ef4214b33018f497cf10daeff9dc85bChris Forbes    }
10699449670637ef4214b33018f497cf10daeff9dc85bChris Forbes
107009a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pSemaphore = GetSemaphoreNode(dev_data, semaphore);
10701f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    if (pSemaphore && pSemaphore->signaled) {
107023251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
10703315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        HandleToUint64(semaphore), __LINE__, VALIDATION_ERROR_16400a0c, "DS",
107043251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkAcquireNextImageKHR: Semaphore must not be currently signaled or in a wait state. %s",
10705315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis                        validation_error_map[VALIDATION_ERROR_16400a0c]);
107065b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10707f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes
107089a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto pFence = GetFenceNode(dev_data, fence);
10709f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    if (pFence) {
107103251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= ValidateFenceForSubmit(dev_data, pFence);
107115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
107124a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes
107139a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto swapchain_data = GetSwapchainNode(dev_data, swapchain);
10714fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes
10715fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes    if (swapchain_data->replaced) {
107163251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
107179b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(swapchain), __LINE__, DRAWSTATE_SWAPCHAIN_REPLACED, "DS",
107183251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkAcquireNextImageKHR: This swapchain has been replaced. The application can still "
107193251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "present any images it has acquired, but cannot acquire any more.");
10720fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes    }
10721fc9f0448c3cb6ba4fc018fefe761bb43a1884846Chris Forbes
107229a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(dev_data->instance_data, dev_data->physical_device);
107234a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes    if (physical_device_state->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState != UNCALLED) {
107246569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski        uint64_t acquired_images = std::count_if(swapchain_data->images.begin(), swapchain_data->images.end(),
107259a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis                                                 [=](VkImage image) { return GetImageState(dev_data, image)->acquired; });
107264a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes        if (acquired_images > swapchain_data->images.size() - physical_device_state->surfaceCapabilities.minImageCount) {
107273251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |=
107286569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski                log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
107299b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(swapchain), __LINE__, DRAWSTATE_SWAPCHAIN_TOO_MANY_IMAGES, "DS",
107306569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski                        "vkAcquireNextImageKHR: Application has already acquired the maximum number of images (0x%" PRIxLEAST64 ")",
107316569ab421f45f905e69fa7345bda4fe5b87e9045Mark Lobodzinski                        acquired_images);
107324a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes        }
107334a5614452104c88cb04390dac882dd94ebdcc3deChris Forbes    }
1073475269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis
1073575269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis    if (swapchain_data->images.size() == 0) {
107363251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
107379b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        HandleToUint64(swapchain), __LINE__, DRAWSTATE_SWAPCHAIN_IMAGES_NOT_FOUND, "DS",
107383251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkAcquireNextImageKHR: No images found to acquire from. Application probably did not call "
107393251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                        "vkGetSwapchainImagesKHR after swapchain creation.");
1074075269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis    }
1074175269fc9e5cc9696ddf3dd28ff201c9b2526dc7aThomas Louis
10742b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    lock.unlock();
107431344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
107443251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
10745f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes
107464a0754042cf090e131e9e769d8a3633c228625beChris Forbes    VkResult result = dev_data->dispatch_table.AcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, pImageIndex);
10747f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes
10748f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    lock.lock();
10749f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    if (result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR) {
10750f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        if (pFence) {
10751f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes            pFence->state = FENCE_INFLIGHT;
10752cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            pFence->signaler.first = VK_NULL_HANDLE;  // ANI isn't on a queue, so this can't participate in a completion proof.
10753f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        }
10754f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes
10755f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        // A successful call to AcquireNextImageKHR counts as a signal operation on semaphore
10756f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        if (pSemaphore) {
10757f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes            pSemaphore->signaled = true;
107589867daedbf52debc77d6568162ee21e071699b80Chris Forbes            pSemaphore->signaler.first = VK_NULL_HANDLE;
10759f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes        }
10760220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes
10761220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes        // Mark the image as acquired.
10762220a9249bd81543e570b3f38c79d9b1e82e0d0dbChris Forbes        auto image = swapchain_data->images[*pImageIndex];
107639a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis        auto image_state = GetImageState(dev_data, image);
107641facd2c91911508b9fb61f54a56269841299f663Tobin Ehlis        image_state->acquired = true;
1076587a57d8e822316de46ee97f514187331b1f4f09dTobin Ehlis        image_state->shared_presentable = swapchain_data->shared_presentable;
107665b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
10767f91af4dfe0646cf509616910a8ec2d72c423ccdaChris Forbes    lock.unlock();
107681344302fce242e654df2fd518b6371a91b8a5c7dTobin Ehlis
107695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return result;
107705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
107715b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
10772f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount,
10773f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski                                                        VkPhysicalDevice *pPhysicalDevices) {
107743251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
1077556e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
10776bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    assert(instance_data);
10777219f00ffed576643641976122fa1db8e5fce5dc1Chris Forbes
10778bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    // For this instance, flag when vkEnumeratePhysicalDevices goes to QUERY_COUNT and then QUERY_DETAILS
10779bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    if (NULL == pPhysicalDevices) {
10780bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        instance_data->vkEnumeratePhysicalDevicesState = QUERY_COUNT;
10781f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    } else {
10782bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        if (UNCALLED == instance_data->vkEnumeratePhysicalDevicesState) {
10783bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            // Flag warning here. You can call this without having queried the count, but it may not be
10784bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            // robust on platforms with multiple physical devices.
107853251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT,
107863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            0, __LINE__, DEVLIMITS_MISSING_QUERY_COUNT, "DL",
107873251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Call sequence has vkEnumeratePhysicalDevices() w/ non-NULL pPhysicalDevices. You should first "
107883251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "call vkEnumeratePhysicalDevices() w/ NULL pPhysicalDevices to query pPhysicalDeviceCount.");
10789cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski        }  // TODO : Could also flag a warning if re-calling this function in QUERY_DETAILS state
10790bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        else if (instance_data->physical_devices_count != *pPhysicalDeviceCount) {
10791bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            // Having actual count match count from app is not a requirement, so this can be a warning
107923251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski            skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
107933251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVLIMITS_COUNT_MISMATCH, "DL",
107943251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Call to vkEnumeratePhysicalDevices() w/ pPhysicalDeviceCount value %u, but actual count "
107953251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "supported by this instance is %u.",
107963251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            *pPhysicalDeviceCount, instance_data->physical_devices_count);
10797bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        }
10798bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        instance_data->vkEnumeratePhysicalDevicesState = QUERY_DETAILS;
10799f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski    }
108003251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) {
10801bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        return VK_ERROR_VALIDATION_FAILED_EXT;
10802bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    }
10803bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    VkResult result = instance_data->dispatch_table.EnumeratePhysicalDevices(instance, pPhysicalDeviceCount, pPhysicalDevices);
10804bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    if (NULL == pPhysicalDevices) {
10805bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        instance_data->physical_devices_count = *pPhysicalDeviceCount;
10806cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    } else if (result == VK_SUCCESS) {  // Save physical devices
10807bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        for (uint32_t i = 0; i < *pPhysicalDeviceCount; i++) {
10808bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            auto &phys_device_state = instance_data->physical_device_map[pPhysicalDevices[i]];
10809bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            phys_device_state.phys_device = pPhysicalDevices[i];
10810bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            // Init actual features for each physical device
10811bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis            instance_data->dispatch_table.GetPhysicalDeviceFeatures(pPhysicalDevices[i], &phys_device_state.features);
10812bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis        }
10813bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    }
10814bfd47e4db53f595683fbe192d73bbda5c56606a6Tobin Ehlis    return result;
10815f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski}
10816f83fcc51d156b056966509bfe4d05c9ccb37ce5dMark Lobodzinski
1081743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis// Common function to handle validation for GetPhysicalDeviceQueueFamilyProperties & 2KHR version
1081843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic bool ValidateCommonGetPhysicalDeviceQueueFamilyProperties(instance_layer_data *instance_data,
1081943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                 PHYSICAL_DEVICE_STATE *pd_state,
108205770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                                 uint32_t requested_queue_family_property_count, bool qfp_null,
108215770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                                 const char *caller_name) {
1082243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    bool skip = false;
108235770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    if (!qfp_null) {
108245770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        // Verify that for each physical device, this command is called first with NULL pQueueFamilyProperties in order to get count
1082543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        if (UNCALLED == pd_state->vkGetPhysicalDeviceQueueFamilyPropertiesState) {
108265770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus            skip |= log_msg(
108275770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
108289b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                HandleToUint64(pd_state->phys_device), __LINE__, DEVLIMITS_MISSING_QUERY_COUNT, "DL",
108295770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                "%s is called with non-NULL pQueueFamilyProperties before obtaining pQueueFamilyPropertyCount. It is recommended "
108305770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                "to first call %s with NULL pQueueFamilyProperties in order to obtain the maximal pQueueFamilyPropertyCount.",
108315770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                caller_name, caller_name);
108325770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus            // Then verify that pCount that is passed in on second call matches what was returned
108335770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        } else if (pd_state->queue_family_count != requested_queue_family_property_count) {
108345770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus            skip |= log_msg(
108355770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
108369b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                HandleToUint64(pd_state->phys_device), __LINE__, DEVLIMITS_COUNT_MISMATCH, "DL",
108375770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                "%s is called with non-NULL pQueueFamilyProperties and pQueueFamilyPropertyCount value %" PRIu32
108385770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                ", but the largest previously returned pQueueFamilyPropertyCount for this physicalDevice is %" PRIu32
108395770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                ". It is recommended to instead receive all the properties by calling %s with pQueueFamilyPropertyCount that was "
108405770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                "previously obtained by calling %s with NULL pQueueFamilyProperties.",
108415770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                caller_name, requested_queue_family_property_count, pd_state->queue_family_count, caller_name, caller_name);
1084243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        }
1084343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        pd_state->vkGetPhysicalDeviceQueueFamilyPropertiesState = QUERY_DETAILS;
1084443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    }
108455770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
1084643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    return skip;
1084743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1084843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1084943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic bool PreCallValidateGetPhysicalDeviceQueueFamilyProperties(instance_layer_data *instance_data,
108505770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                                  PHYSICAL_DEVICE_STATE *pd_state,
108515770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                                  uint32_t *pQueueFamilyPropertyCount,
1085243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                  VkQueueFamilyProperties *pQueueFamilyProperties) {
108535770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    return ValidateCommonGetPhysicalDeviceQueueFamilyProperties(instance_data, pd_state, *pQueueFamilyPropertyCount,
108545770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                                (nullptr == pQueueFamilyProperties),
1085543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                "vkGetPhysicalDeviceQueueFamilyProperties()");
1085643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1085743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1085843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic bool PreCallValidateGetPhysicalDeviceQueueFamilyProperties2KHR(instance_layer_data *instance_data,
1085943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                      PHYSICAL_DEVICE_STATE *pd_state,
1086043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                      uint32_t *pQueueFamilyPropertyCount,
1086143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                      VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
108625770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    return ValidateCommonGetPhysicalDeviceQueueFamilyProperties(instance_data, pd_state, *pQueueFamilyPropertyCount,
108635770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                                (nullptr == pQueueFamilyProperties),
1086443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                "vkGetPhysicalDeviceQueueFamilyProperties2KHR()");
1086543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1086643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1086743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis// Common function to update state for GetPhysicalDeviceQueueFamilyProperties & 2KHR version
1086843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic void StateUpdateCommonGetPhysicalDeviceQueueFamilyProperties(PHYSICAL_DEVICE_STATE *pd_state, uint32_t count,
1086943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                    VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
1087043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    if (!pQueueFamilyProperties) {
108715770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        if (UNCALLED == pd_state->vkGetPhysicalDeviceQueueFamilyPropertiesState)
108725770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus            pd_state->vkGetPhysicalDeviceQueueFamilyPropertiesState = QUERY_COUNT;
108735770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        pd_state->queue_family_count = count;
1087443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    } else {  // Save queue family properties
108755770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        pd_state->vkGetPhysicalDeviceQueueFamilyPropertiesState = QUERY_DETAILS;
108765770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        pd_state->queue_family_count = std::max(pd_state->queue_family_count, count);
108775770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
108785770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        pd_state->queue_family_properties.resize(std::max(static_cast<uint32_t>(pd_state->queue_family_properties.size()), count));
108795770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus        for (uint32_t i = 0; i < count; ++i) {
1088043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            pd_state->queue_family_properties[i] = pQueueFamilyProperties[i].queueFamilyProperties;
1088143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        }
1088243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    }
1088343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1088443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1088543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic void PostCallRecordGetPhysicalDeviceQueueFamilyProperties(PHYSICAL_DEVICE_STATE *pd_state, uint32_t count,
1088643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                 VkQueueFamilyProperties *pQueueFamilyProperties) {
1088743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    VkQueueFamilyProperties2KHR *pqfp = nullptr;
1088843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    std::vector<VkQueueFamilyProperties2KHR> qfp;
1088943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    qfp.resize(count);
1089043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    if (pQueueFamilyProperties) {
1089143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        for (uint32_t i = 0; i < count; ++i) {
1089243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            qfp[i].sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR;
1089343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            qfp[i].pNext = nullptr;
1089443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis            qfp[i].queueFamilyProperties = pQueueFamilyProperties[i];
1089543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        }
1089643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis        pqfp = qfp.data();
1089743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    }
1089843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    StateUpdateCommonGetPhysicalDeviceQueueFamilyProperties(pd_state, count, pqfp);
1089943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1090043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1090143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlisstatic void PostCallRecordGetPhysicalDeviceQueueFamilyProperties2KHR(PHYSICAL_DEVICE_STATE *pd_state, uint32_t count,
1090243947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                     VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
1090343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    StateUpdateCommonGetPhysicalDeviceQueueFamilyProperties(pd_state, count, pQueueFamilyProperties);
1090443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1090543947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
109065770f8ad21c40b2475201e73e9368a899b6886d0Petr KrausVKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice,
109075770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                                  uint32_t *pQueueFamilyPropertyCount,
10908bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                  VkQueueFamilyProperties *pQueueFamilyProperties) {
1090956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
109109a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
1091143947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    assert(physical_device_state);
109125770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    std::unique_lock<std::mutex> lock(global_lock);
109135770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
109145770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    bool skip = PreCallValidateGetPhysicalDeviceQueueFamilyProperties(instance_data, physical_device_state,
109155770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                                      pQueueFamilyPropertyCount, pQueueFamilyProperties);
109165770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
109175770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    lock.unlock();
109185770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
109195770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    if (skip) return;
109205770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
109215770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, pQueueFamilyPropertyCount,
109225770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus                                                                         pQueueFamilyProperties);
109235770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
109245770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    lock.lock();
109255770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    PostCallRecordGetPhysicalDeviceQueueFamilyProperties(physical_device_state, *pQueueFamilyPropertyCount, pQueueFamilyProperties);
1092643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis}
1092743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis
1092843947a6175e3e942e04d902f4d18928168e2d0dbTobin EhlisVKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceQueueFamilyProperties2KHR(VkPhysicalDevice physicalDevice,
1092943947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                      uint32_t *pQueueFamilyPropertyCount,
1093043947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                      VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
1093156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
109329a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
1093343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    assert(physical_device_state);
109345770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    std::unique_lock<std::mutex> lock(global_lock);
109355770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
1093643947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    bool skip = PreCallValidateGetPhysicalDeviceQueueFamilyProperties2KHR(instance_data, physical_device_state,
1093743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                          pQueueFamilyPropertyCount, pQueueFamilyProperties);
109385770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
109395770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    lock.unlock();
109405770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
109415770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    if (skip) return;
109425770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
1094343947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    instance_data->dispatch_table.GetPhysicalDeviceQueueFamilyProperties2KHR(physicalDevice, pQueueFamilyPropertyCount,
1094443947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                                             pQueueFamilyProperties);
109455770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus
109465770f8ad21c40b2475201e73e9368a899b6886d0Petr Kraus    lock.lock();
1094743947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis    PostCallRecordGetPhysicalDeviceQueueFamilyProperties2KHR(physical_device_state, *pQueueFamilyPropertyCount,
1094843947a6175e3e942e04d902f4d18928168e2d0dbTobin Ehlis                                                             pQueueFamilyProperties);
10949cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski}
10950cd569b3559a7f8dca06012165480a4e6d7e6c492Mark Lobodzinski
10951bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskitemplate <typename TCreateInfo, typename FPtr>
10952bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskistatic VkResult CreateSurface(VkInstance instance, TCreateInfo const *pCreateInfo, VkAllocationCallbacks const *pAllocator,
10953bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                              VkSurfaceKHR *pSurface, FPtr fptr) {
1095456e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
10955747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
10956747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    // Call down the call chain:
10957747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    VkResult result = (instance_data->dispatch_table.*fptr)(instance, pCreateInfo, pAllocator, pSurface);
10958747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
10959747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    if (result == VK_SUCCESS) {
10960747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        std::unique_lock<std::mutex> lock(global_lock);
10961747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        instance_data->surface_map[*pSurface] = SURFACE_STATE(*pSurface);
10962747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        lock.unlock();
10963747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
10964747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
10965747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return result;
10966747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
10967747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
10968747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR void VKAPI_CALL DestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks *pAllocator) {
109693251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
1097056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
10971747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
109729a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto surface_state = GetSurfaceState(instance_data, surface);
10973747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
10974747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    if (surface_state) {
10975747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        // TODO: track swapchains created from this surface.
10976747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        instance_data->surface_map.erase(surface);
10977747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
10978747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    lock.unlock();
10979747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
109803251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (!skip) {
10981747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        // Call down the call chain:
10982747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes        instance_data->dispatch_table.DestroySurfaceKHR(instance, surface, pAllocator);
10983747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    }
10984747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
10985747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
109866f2ed666809272002a31b3b4f8adf6581cb41819Norbert NopperVKAPI_ATTR VkResult VKAPI_CALL CreateDisplayPlaneSurfaceKHR(VkInstance instance, const VkDisplaySurfaceCreateInfoKHR *pCreateInfo,
109876f2ed666809272002a31b3b4f8adf6581cb41819Norbert Nopper                                                            const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
109886f2ed666809272002a31b3b4f8adf6581cb41819Norbert Nopper    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateDisplayPlaneSurfaceKHR);
109896f2ed666809272002a31b3b4f8adf6581cb41819Norbert Nopper}
109906f2ed666809272002a31b3b4f8adf6581cb41819Norbert Nopper
10991747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_ANDROID_KHR
10992747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR *pCreateInfo,
10993747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                       const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
10994747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateAndroidSurfaceKHR);
10995747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
10996cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_ANDROID_KHR
10997747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
10998747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_MIR_KHR
10999747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateMirSurfaceKHR(VkInstance instance, const VkMirSurfaceCreateInfoKHR *pCreateInfo,
11000747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                   const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
11001747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateMirSurfaceKHR);
11002747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11003f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11004f25d461667ca2db55147d2be49f179945edf24dbPetr KrausVKAPI_ATTR VkBool32 VKAPI_CALL GetPhysicalDeviceMirPresentationSupportKHR(VkPhysicalDevice physicalDevice,
11005f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                                                          uint32_t queueFamilyIndex, MirConnection *connection) {
11006f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    bool skip = false;
11007f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
11008f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11009f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    std::unique_lock<std::mutex> lock(global_lock);
11010f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    const auto pd_state = GetPhysicalDeviceState(instance_data, physicalDevice);
11011f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11012315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= ValidatePhysicalDeviceQueueFamily(instance_data, pd_state, queueFamilyIndex, VALIDATION_ERROR_2d2009e2,
11013f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                              "vkGetPhysicalDeviceMirPresentationSupportKHR", "queueFamilyIndex");
11014f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11015f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    lock.unlock();
11016f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11017f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    if (skip) return VK_FALSE;
11018f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11019f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    // Call down the call chain:
11020f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    VkBool32 result =
11021f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus        instance_data->dispatch_table.GetPhysicalDeviceMirPresentationSupportKHR(physicalDevice, queueFamilyIndex, connection);
11022f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11023f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    return result;
11024f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus}
11025cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_MIR_KHR
11026747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11027747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WAYLAND_KHR
11028747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateWaylandSurfaceKHR(VkInstance instance, const VkWaylandSurfaceCreateInfoKHR *pCreateInfo,
11029747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                       const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
11030a9c6cc532ce0ef61d48d1419a96aae51b0e4c64aTobin Ehlis    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateWaylandSurfaceKHR);
11031747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11032f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11033f25d461667ca2db55147d2be49f179945edf24dbPetr KrausVKAPI_ATTR VkBool32 VKAPI_CALL GetPhysicalDeviceWaylandPresentationSupportKHR(VkPhysicalDevice physicalDevice,
11034f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                                                              uint32_t queueFamilyIndex,
11035f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                                                              struct wl_display *display) {
11036f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    bool skip = false;
11037f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
11038f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11039f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    std::unique_lock<std::mutex> lock(global_lock);
11040f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    const auto pd_state = GetPhysicalDeviceState(instance_data, physicalDevice);
11041f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11042315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= ValidatePhysicalDeviceQueueFamily(instance_data, pd_state, queueFamilyIndex, VALIDATION_ERROR_2f000a34,
11043f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                              "vkGetPhysicalDeviceWaylandPresentationSupportKHR", "queueFamilyIndex");
11044f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11045f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    lock.unlock();
11046f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11047f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    if (skip) return VK_FALSE;
11048f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11049f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    // Call down the call chain:
11050f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    VkBool32 result =
11051f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus        instance_data->dispatch_table.GetPhysicalDeviceWaylandPresentationSupportKHR(physicalDevice, queueFamilyIndex, display);
11052f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11053f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    return result;
11054f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus}
11055cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_WAYLAND_KHR
11056747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11057747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_WIN32_KHR
11058747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateWin32SurfaceKHR(VkInstance instance, const VkWin32SurfaceCreateInfoKHR *pCreateInfo,
11059747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                     const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
11060747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateWin32SurfaceKHR);
11061747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11062f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11063f25d461667ca2db55147d2be49f179945edf24dbPetr KrausVKAPI_ATTR VkBool32 VKAPI_CALL GetPhysicalDeviceWin32PresentationSupportKHR(VkPhysicalDevice physicalDevice,
11064f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                                                            uint32_t queueFamilyIndex) {
11065f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    bool skip = false;
11066f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
11067f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11068f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    std::unique_lock<std::mutex> lock(global_lock);
11069f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    const auto pd_state = GetPhysicalDeviceState(instance_data, physicalDevice);
11070f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11071315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= ValidatePhysicalDeviceQueueFamily(instance_data, pd_state, queueFamilyIndex, VALIDATION_ERROR_2f200a3a,
11072f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                              "vkGetPhysicalDeviceWin32PresentationSupportKHR", "queueFamilyIndex");
11073f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11074f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    lock.unlock();
11075f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11076f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    if (skip) return VK_FALSE;
11077f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11078f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    // Call down the call chain:
11079f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    VkBool32 result = instance_data->dispatch_table.GetPhysicalDeviceWin32PresentationSupportKHR(physicalDevice, queueFamilyIndex);
11080f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11081f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    return result;
11082f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus}
11083cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_WIN32_KHR
11084747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11085747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XCB_KHR
11086747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateXcbSurfaceKHR(VkInstance instance, const VkXcbSurfaceCreateInfoKHR *pCreateInfo,
11087747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes                                                   const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
11088747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateXcbSurfaceKHR);
11089747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11090f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11091f25d461667ca2db55147d2be49f179945edf24dbPetr KrausVKAPI_ATTR VkBool32 VKAPI_CALL GetPhysicalDeviceXcbPresentationSupportKHR(VkPhysicalDevice physicalDevice,
11092f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                                                          uint32_t queueFamilyIndex, xcb_connection_t *connection,
11093f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                                                          xcb_visualid_t visual_id) {
11094f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    bool skip = false;
11095f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
11096f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11097f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    std::unique_lock<std::mutex> lock(global_lock);
11098f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    const auto pd_state = GetPhysicalDeviceState(instance_data, physicalDevice);
11099f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11100315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= ValidatePhysicalDeviceQueueFamily(instance_data, pd_state, queueFamilyIndex, VALIDATION_ERROR_2f400a40,
11101f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                              "vkGetPhysicalDeviceXcbPresentationSupportKHR", "queueFamilyIndex");
11102f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11103f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    lock.unlock();
11104f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11105f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    if (skip) return VK_FALSE;
11106f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11107f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    // Call down the call chain:
11108f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    VkBool32 result = instance_data->dispatch_table.GetPhysicalDeviceXcbPresentationSupportKHR(physicalDevice, queueFamilyIndex,
11109f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                                                                               connection, visual_id);
11110f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11111f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    return result;
11112f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus}
11113cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_XCB_KHR
11114747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
11115747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes#ifdef VK_USE_PLATFORM_XLIB_KHR
11116747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL CreateXlibSurfaceKHR(VkInstance instance, const VkXlibSurfaceCreateInfoKHR *pCreateInfo,
11117bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                    const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
11118747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes    return CreateSurface(instance, pCreateInfo, pAllocator, pSurface, &VkLayerInstanceDispatchTable::CreateXlibSurfaceKHR);
11119747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes}
11120f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11121f25d461667ca2db55147d2be49f179945edf24dbPetr KrausVKAPI_ATTR VkBool32 VKAPI_CALL GetPhysicalDeviceXlibPresentationSupportKHR(VkPhysicalDevice physicalDevice,
11122f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                                                           uint32_t queueFamilyIndex, Display *dpy,
11123f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                                                           VisualID visualID) {
11124f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    bool skip = false;
11125f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
11126f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11127f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    std::unique_lock<std::mutex> lock(global_lock);
11128f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    const auto pd_state = GetPhysicalDeviceState(instance_data, physicalDevice);
11129f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11130315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= ValidatePhysicalDeviceQueueFamily(instance_data, pd_state, queueFamilyIndex, VALIDATION_ERROR_2f600a46,
11131f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                              "vkGetPhysicalDeviceXlibPresentationSupportKHR", "queueFamilyIndex");
11132f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11133f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    lock.unlock();
11134f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11135f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    if (skip) return VK_FALSE;
11136f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11137f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    // Call down the call chain:
11138f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    VkBool32 result =
11139f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus        instance_data->dispatch_table.GetPhysicalDeviceXlibPresentationSupportKHR(physicalDevice, queueFamilyIndex, dpy, visualID);
11140f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11141f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    return result;
11142f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus}
11143cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski#endif  // VK_USE_PLATFORM_XLIB_KHR
11144747ce6dd32eafd93da3dc12a6ffd670e746ae453Chris Forbes
1114540921785005eb449ec7c18229f0d84c879708b8aChris ForbesVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
1114640921785005eb449ec7c18229f0d84c879708b8aChris Forbes                                                                       VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) {
1114756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    auto instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
1114840921785005eb449ec7c18229f0d84c879708b8aChris Forbes
1114940921785005eb449ec7c18229f0d84c879708b8aChris Forbes    std::unique_lock<std::mutex> lock(global_lock);
111509a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
1115140921785005eb449ec7c18229f0d84c879708b8aChris Forbes    lock.unlock();
1115240921785005eb449ec7c18229f0d84c879708b8aChris Forbes
11153bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result =
11154bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        instance_data->dispatch_table.GetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, pSurfaceCapabilities);
1115540921785005eb449ec7c18229f0d84c879708b8aChris Forbes
1115640921785005eb449ec7c18229f0d84c879708b8aChris Forbes    if (result == VK_SUCCESS) {
1115740921785005eb449ec7c18229f0d84c879708b8aChris Forbes        physical_device_state->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState = QUERY_DETAILS;
1115840921785005eb449ec7c18229f0d84c879708b8aChris Forbes        physical_device_state->surfaceCapabilities = *pSurfaceCapabilities;
1115940921785005eb449ec7c18229f0d84c879708b8aChris Forbes    }
1116040921785005eb449ec7c18229f0d84c879708b8aChris Forbes
1116140921785005eb449ec7c18229f0d84c879708b8aChris Forbes    return result;
1116240921785005eb449ec7c18229f0d84c879708b8aChris Forbes}
1116340921785005eb449ec7c18229f0d84c879708b8aChris Forbes
1116435b630211642e709485879a2e8859736f0ab16a0Mike Schuchardtstatic void PostCallRecordGetPhysicalDeviceSurfaceCapabilities2KHR(instance_layer_data *instanceData,
1116535b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                                   VkPhysicalDevice physicalDevice,
1116635b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                                   VkSurfaceCapabilities2KHR *pSurfaceCapabilities) {
1116735b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    std::unique_lock<std::mutex> lock(global_lock);
1116835b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    auto physicalDeviceState = GetPhysicalDeviceState(instanceData, physicalDevice);
1116935b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState = QUERY_DETAILS;
1117035b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->surfaceCapabilities = pSurfaceCapabilities->surfaceCapabilities;
1117135b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt}
1117235b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
1117335b630211642e709485879a2e8859736f0ab16a0Mike SchuchardtVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceCapabilities2KHR(VkPhysicalDevice physicalDevice,
1117435b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                                        const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
1117535b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                                        VkSurfaceCapabilities2KHR *pSurfaceCapabilities) {
1117635b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    auto instanceData = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
1117735b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
1117835b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    auto result =
1117935b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        instanceData->dispatch_table.GetPhysicalDeviceSurfaceCapabilities2KHR(physicalDevice, pSurfaceInfo, pSurfaceCapabilities);
1118035b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
1118135b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    if (result == VK_SUCCESS) {
1118235b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        PostCallRecordGetPhysicalDeviceSurfaceCapabilities2KHR(instanceData, physicalDevice, pSurfaceCapabilities);
1118335b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    }
1118435b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
1118535b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    return result;
1118635b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt}
1118735b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
1118835b630211642e709485879a2e8859736f0ab16a0Mike Schuchardtstatic void PostCallRecordGetPhysicalDeviceSurfaceCapabilities2EXT(instance_layer_data *instanceData,
1118935b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                                   VkPhysicalDevice physicalDevice,
1119035b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                                   VkSurfaceCapabilities2EXT *pSurfaceCapabilities) {
1119135b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    std::unique_lock<std::mutex> lock(global_lock);
1119235b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    auto physicalDeviceState = GetPhysicalDeviceState(instanceData, physicalDevice);
1119335b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->vkGetPhysicalDeviceSurfaceCapabilitiesKHRState = QUERY_DETAILS;
1119435b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->surfaceCapabilities.minImageCount = pSurfaceCapabilities->minImageCount;
1119535b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->surfaceCapabilities.maxImageCount = pSurfaceCapabilities->maxImageCount;
1119635b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->surfaceCapabilities.currentExtent = pSurfaceCapabilities->currentExtent;
1119735b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->surfaceCapabilities.minImageExtent = pSurfaceCapabilities->minImageExtent;
1119835b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->surfaceCapabilities.maxImageExtent = pSurfaceCapabilities->maxImageExtent;
1119935b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->surfaceCapabilities.maxImageArrayLayers = pSurfaceCapabilities->maxImageArrayLayers;
1120035b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->surfaceCapabilities.supportedTransforms = pSurfaceCapabilities->supportedTransforms;
1120135b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->surfaceCapabilities.currentTransform = pSurfaceCapabilities->currentTransform;
1120235b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->surfaceCapabilities.supportedCompositeAlpha = pSurfaceCapabilities->supportedCompositeAlpha;
1120335b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    physicalDeviceState->surfaceCapabilities.supportedUsageFlags = pSurfaceCapabilities->supportedUsageFlags;
1120435b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt}
1120535b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
1120635b630211642e709485879a2e8859736f0ab16a0Mike SchuchardtVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceCapabilities2EXT(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
1120735b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                                        VkSurfaceCapabilities2EXT *pSurfaceCapabilities) {
1120835b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    auto instanceData = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
1120935b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
1121035b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    auto result =
1121135b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        instanceData->dispatch_table.GetPhysicalDeviceSurfaceCapabilities2EXT(physicalDevice, surface, pSurfaceCapabilities);
1121235b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
1121335b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    if (result == VK_SUCCESS) {
1121435b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        PostCallRecordGetPhysicalDeviceSurfaceCapabilities2EXT(instanceData, physicalDevice, pSurfaceCapabilities);
1121535b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    }
1121635b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
1121735b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    return result;
1121835b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt}
1121935b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
11220418a8711f3301f3027a900bb45daaf0892f4e644Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex,
11221418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes                                                                  VkSurfaceKHR surface, VkBool32 *pSupported) {
11222f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    bool skip = false;
1122356e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    auto instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
11224f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11225418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
11226f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    const auto pd_state = GetPhysicalDeviceState(instance_data, physicalDevice);
112279a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto surface_state = GetSurfaceState(instance_data, surface);
11228f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11229315b15c3d74eb1df11b992c2b9922cf98e939eb8Tobin Ehlis    skip |= ValidatePhysicalDeviceQueueFamily(instance_data, pd_state, queueFamilyIndex, VALIDATION_ERROR_2ee009ea,
11230f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus                                              "vkGetPhysicalDeviceSurfaceSupportKHR", "queueFamilyIndex");
11231f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11232418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    lock.unlock();
11233418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes
11234f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
11235f25d461667ca2db55147d2be49f179945edf24dbPetr Kraus
11236bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result =
11237bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        instance_data->dispatch_table.GetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, surface, pSupported);
11238418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes
11239418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    if (result == VK_SUCCESS) {
112400bbc015828bdb99e85e6731ce92428557902701fPetr Kraus        surface_state->gpu_queue_support[{physicalDevice, queueFamilyIndex}] = (*pSupported == VK_TRUE);
11241418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    }
11242418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes
11243418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes    return result;
11244418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes}
11245418a8711f3301f3027a900bb45daaf0892f4e644Chris Forbes
112469e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
112479e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                                                                       uint32_t *pPresentModeCount,
112489e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                                                                       VkPresentModeKHR *pPresentModes) {
112493251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
1125056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    auto instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
112519e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
112529e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    // TODO: this isn't quite right. available modes may differ by surface AND physical device.
112539a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
11254bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto &call_state = physical_device_state->vkGetPhysicalDeviceSurfacePresentModesKHRState;
112559e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
112569e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    if (pPresentModes) {
112579e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        // Compare the preliminary value of *pPresentModeCount with the value this time:
11258bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto prev_mode_count = (uint32_t)physical_device_state->present_modes.size();
112599e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        switch (call_state) {
11260cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case UNCALLED:
112613251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(
11262bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
112639b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    HandleToUint64(physicalDevice), __LINE__, DEVLIMITS_MUST_QUERY_COUNT, "DL",
11264cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "vkGetPhysicalDeviceSurfacePresentModesKHR() called with non-NULL pPresentModeCount; but no prior positive "
11265cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "value has been seen for pPresentModeCount.");
11266cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
11267cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
11268cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // both query count and query details
11269cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (*pPresentModeCount != prev_mode_count) {
112703251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
112719b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, HandleToUint64(physicalDevice), __LINE__,
112729b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                                    DEVLIMITS_COUNT_MISMATCH, "DL",
112733251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "vkGetPhysicalDeviceSurfacePresentModesKHR() called with *pPresentModeCount (%u) that "
112743251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "differs from the value "
112753251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    "(%u) that was returned when pPresentModes was NULL.",
112763251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                    *pPresentModeCount, prev_mode_count);
11277cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
11278cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
112799e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
112809e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    }
112819e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    lock.unlock();
112829e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
112833251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
112849e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
11285bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto result = instance_data->dispatch_table.GetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, pPresentModeCount,
11286bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                        pPresentModes);
112879e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
112889e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
112899e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        lock.lock();
112909e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
112919e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        if (*pPresentModeCount) {
11292cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (call_state < QUERY_COUNT) call_state = QUERY_COUNT;
112939e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            if (*pPresentModeCount > physical_device_state->present_modes.size())
112949e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                physical_device_state->present_modes.resize(*pPresentModeCount);
112959e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
112969e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        if (pPresentModes) {
11297cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (call_state < QUERY_DETAILS) call_state = QUERY_DETAILS;
112989e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            for (uint32_t i = 0; i < *pPresentModeCount; i++) {
112999e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes                physical_device_state->present_modes[i] = pPresentModes[i];
113009e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes            }
113019e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
113025faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    }
113035faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
113045faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    return result;
113055faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes}
113065faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
113075faa662f6859b01c72d79027abde363d5f10dcd7Chris ForbesVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
113085faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                                                                  uint32_t *pSurfaceFormatCount,
113095faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                                                                  VkSurfaceFormatKHR *pSurfaceFormats) {
113103251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
1131156e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    auto instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
113125faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    std::unique_lock<std::mutex> lock(global_lock);
113139a9a0db2a973034d4286b6d4c62a46beb7641791Tobin Ehlis    auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
11314bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski    auto &call_state = physical_device_state->vkGetPhysicalDeviceSurfaceFormatsKHRState;
113155faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
113165faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    if (pSurfaceFormats) {
11317bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski        auto prev_format_count = (uint32_t)physical_device_state->surface_formats.size();
113185faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
113195faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        switch (call_state) {
11320cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            case UNCALLED:
11321cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // Since we haven't recorded a preliminary value of *pSurfaceFormatCount, that likely means that the application
11322cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // didn't
11323cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                // previously call this function with a NULL value of pSurfaceFormats:
113243251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(
11325bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                    instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
113269b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                    HandleToUint64(physicalDevice), __LINE__, DEVLIMITS_MUST_QUERY_COUNT, "DL",
11327cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "vkGetPhysicalDeviceSurfaceFormatsKHR() called with non-NULL pSurfaceFormatCount; but no prior positive "
11328cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                    "value has been seen for pSurfaceFormats.");
11329cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
11330cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            default:
11331cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                if (prev_format_count != *pSurfaceFormatCount) {
113323251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                    skip |= log_msg(
11333cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
113349b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                        VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, HandleToUint64(physicalDevice), __LINE__,
11335cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        DEVLIMITS_COUNT_MISMATCH, "DL",
11336cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "vkGetPhysicalDeviceSurfaceFormatsKHR() called with non-NULL pSurfaceFormatCount, and with pSurfaceFormats "
11337cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "set "
11338cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "to "
11339cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        "a value (%u) that is greater than the value (%u) that was returned when pSurfaceFormatCount was NULL.",
11340cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                        *pSurfaceFormatCount, prev_format_count);
11341cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                }
11342cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski                break;
113439e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes        }
113449e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    }
113455faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    lock.unlock();
113465faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
113473251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
113489e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
113495faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    // Call down the call chain:
113505faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    auto result = instance_data->dispatch_table.GetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, pSurfaceFormatCount,
113515faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                                                                                   pSurfaceFormats);
113525faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
113535faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
113545faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        lock.lock();
113555faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes
113565faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        if (*pSurfaceFormatCount) {
11357cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (call_state < QUERY_COUNT) call_state = QUERY_COUNT;
113585faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            if (*pSurfaceFormatCount > physical_device_state->surface_formats.size())
113595faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                physical_device_state->surface_formats.resize(*pSurfaceFormatCount);
113605faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        }
113615faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        if (pSurfaceFormats) {
11362cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski            if (call_state < QUERY_DETAILS) call_state = QUERY_DETAILS;
113635faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            for (uint32_t i = 0; i < *pSurfaceFormatCount; i++) {
113645faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes                physical_device_state->surface_formats[i] = pSurfaceFormats[i];
113655faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes            }
113665faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes        }
113675faa662f6859b01c72d79027abde363d5f10dcd7Chris Forbes    }
113689e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes    return result;
113699e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes}
113709e8e286e0ca0c7cd911c3e7ba3ddd1aceb29cbe9Chris Forbes
1137135b630211642e709485879a2e8859736f0ab16a0Mike Schuchardtstatic void PostCallRecordGetPhysicalDeviceSurfaceFormats2KHR(instance_layer_data *instanceData, VkPhysicalDevice physicalDevice,
1137235b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                              uint32_t *pSurfaceFormatCount, VkSurfaceFormat2KHR *pSurfaceFormats) {
1137335b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    std::unique_lock<std::mutex> lock(global_lock);
1137435b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    auto physicalDeviceState = GetPhysicalDeviceState(instanceData, physicalDevice);
1137535b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    if (*pSurfaceFormatCount) {
1137635b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        if (physicalDeviceState->vkGetPhysicalDeviceSurfaceFormatsKHRState < QUERY_COUNT) {
1137735b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt            physicalDeviceState->vkGetPhysicalDeviceSurfaceFormatsKHRState = QUERY_COUNT;
1137835b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        }
1137935b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        if (*pSurfaceFormatCount > physicalDeviceState->surface_formats.size())
1138035b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt            physicalDeviceState->surface_formats.resize(*pSurfaceFormatCount);
1138135b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    }
1138235b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    if (pSurfaceFormats) {
1138335b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        if (physicalDeviceState->vkGetPhysicalDeviceSurfaceFormatsKHRState < QUERY_DETAILS) {
1138435b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt            physicalDeviceState->vkGetPhysicalDeviceSurfaceFormatsKHRState = QUERY_DETAILS;
1138535b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        }
1138635b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        for (uint32_t i = 0; i < *pSurfaceFormatCount; i++) {
1138735b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt            physicalDeviceState->surface_formats[i] = pSurfaceFormats[i].surfaceFormat;
1138835b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        }
1138935b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    }
1139035b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt}
1139135b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
1139235b630211642e709485879a2e8859736f0ab16a0Mike SchuchardtVKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceFormats2KHR(VkPhysicalDevice physicalDevice,
1139335b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                                   const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
1139435b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                                   uint32_t *pSurfaceFormatCount,
1139535b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                                   VkSurfaceFormat2KHR *pSurfaceFormats) {
1139635b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    auto instanceData = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
1139735b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    auto result = instanceData->dispatch_table.GetPhysicalDeviceSurfaceFormats2KHR(physicalDevice, pSurfaceInfo,
1139835b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt                                                                                   pSurfaceFormatCount, pSurfaceFormats);
1139935b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
1140035b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt        PostCallRecordGetPhysicalDeviceSurfaceFormats2KHR(instanceData, physicalDevice, pSurfaceFormatCount, pSurfaceFormats);
1140135b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    }
1140235b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt    return result;
1140335b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt}
1140435b630211642e709485879a2e8859736f0ab16a0Mike Schuchardt
11405bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateDebugReportCallbackEXT(VkInstance instance,
11406bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                            const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
11407bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                            const VkAllocationCallbacks *pAllocator,
11408bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                            VkDebugReportCallbackEXT *pMsgCallback) {
1140956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
114109172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    VkResult res = instance_data->dispatch_table.CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
114115b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    if (VK_SUCCESS == res) {
11412b9e992386a44404152747d66817a733aa127e281Jeremy Hayes        std::lock_guard<std::mutex> lock(global_lock);
114138860b85a52096f9f9b28616bc37feed505497a54Chris Forbes        res = layer_create_msg_callback(instance_data->report_data, false, pCreateInfo, pAllocator, pMsgCallback);
114145b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    }
114155b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis    return res;
114165b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
114175b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11418bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT msgCallback,
1141989d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu                                                         const VkAllocationCallbacks *pAllocator) {
1142056e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
114219172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    instance_data->dispatch_table.DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);
11422b9e992386a44404152747d66817a733aa127e281Jeremy Hayes    std::lock_guard<std::mutex> lock(global_lock);
114238860b85a52096f9f9b28616bc37feed505497a54Chris Forbes    layer_destroy_msg_callback(instance_data->report_data, msgCallback, pAllocator);
114245b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
114255b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11426bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags,
11427bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 VkDebugReportObjectTypeEXT objType, uint64_t object, size_t location,
11428bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                 int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
1142956e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
114309172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    instance_data->dispatch_table.DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, pMsg);
114315b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
114325b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
11433bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties) {
11434a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return util_GetLayerProperties(1, &global_layer, pCount, pProperties);
11435a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu}
11436a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu
11437bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
11438bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                              VkLayerProperties *pProperties) {
11439a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return util_GetLayerProperties(1, &global_layer, pCount, pProperties);
11440a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu}
11441a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu
11442bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
11443bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                    VkExtensionProperties *pProperties) {
11444a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    if (pLayerName && !strcmp(pLayerName, global_layer.layerName))
11445a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu        return util_GetExtensionProperties(1, instance_extensions, pCount, pProperties);
11446a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu
11447a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return VK_ERROR_LAYER_NOT_PRESENT;
11448a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu}
11449a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu
11450bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char *pLayerName,
11451bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                  uint32_t *pCount, VkExtensionProperties *pProperties) {
11452cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (pLayerName && !strcmp(pLayerName, global_layer.layerName)) return util_GetExtensionProperties(0, NULL, pCount, pProperties);
11453a8f4a23b1e9c068717eda47cc583a93f447c77e3Chia-I Wu
11454a8f4a23b1e9c068717eda47cc583a93f447c77e3Chia-I Wu    assert(physicalDevice);
11455a8f4a23b1e9c068717eda47cc583a93f447c77e3Chia-I Wu
1145656e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
114579172b640a0ae6a92f24ad0609d92b2c228cde89cChris Forbes    return instance_data->dispatch_table.EnumerateDeviceExtensionProperties(physicalDevice, NULL, pCount, pProperties);
1145808939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu}
1145908939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu
11460582b6ed09649188d55ed3b6237352caf9f3384a9Mike WeiblenVKAPI_ATTR VkResult VKAPI_CALL EnumeratePhysicalDeviceGroupsKHX(
11461582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen    VkInstance instance, uint32_t *pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupPropertiesKHX *pPhysicalDeviceGroupProperties) {
114623251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski    bool skip = false;
11463582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
11464582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen
11465582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen    if (instance_data) {
11466582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        // For this instance, flag when EnumeratePhysicalDeviceGroupsKHX goes to QUERY_COUNT and then QUERY_DETAILS.
11467582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        if (NULL == pPhysicalDeviceGroupProperties) {
11468582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            instance_data->vkEnumeratePhysicalDeviceGroupsState = QUERY_COUNT;
11469582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        } else {
11470582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            if (UNCALLED == instance_data->vkEnumeratePhysicalDeviceGroupsState) {
11471582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                // Flag warning here. You can call this without having queried the count, but it may not be
11472582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                // robust on platforms with multiple physical devices.
114733251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
114743251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, 0, __LINE__, DEVLIMITS_MISSING_QUERY_COUNT, "DL",
114753251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "Call sequence has vkEnumeratePhysicalDeviceGroupsKHX() w/ non-NULL "
114763251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "pPhysicalDeviceGroupProperties. You should first "
114773251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "call vkEnumeratePhysicalDeviceGroupsKHX() w/ NULL pPhysicalDeviceGroupProperties to query "
114783251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                                "pPhysicalDeviceGroupCount.");
11479582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            } // TODO : Could also flag a warning if re-calling this function in QUERY_DETAILS state
11480582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            else if (instance_data->physical_device_groups_count != *pPhysicalDeviceGroupCount) {
11481582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                // Having actual count match count from app is not a requirement, so this can be a warning
114823251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                skip |=
11483582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                    log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
114843251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__, DEVLIMITS_COUNT_MISMATCH, "DL",
114853251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "Call to vkEnumeratePhysicalDeviceGroupsKHX() w/ pPhysicalDeviceGroupCount value %u, but actual count "
114863251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            "supported by this instance is %u.",
114873251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski                            *pPhysicalDeviceGroupCount, instance_data->physical_device_groups_count);
11488582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            }
11489582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            instance_data->vkEnumeratePhysicalDeviceGroupsState = QUERY_DETAILS;
11490582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        }
114913251dd855490066e66a663dece5afee8ca0b95cdMark Lobodzinski        if (skip) {
11492582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            return VK_ERROR_VALIDATION_FAILED_EXT;
11493582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        }
11494582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        VkResult result = instance_data->dispatch_table.EnumeratePhysicalDeviceGroupsKHX(instance, pPhysicalDeviceGroupCount,
11495582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            pPhysicalDeviceGroupProperties);
11496582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        if (NULL == pPhysicalDeviceGroupProperties) {
11497582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            instance_data->physical_device_groups_count = *pPhysicalDeviceGroupCount;
11498582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        } else if (result == VK_SUCCESS) { // Save physical devices
11499582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            for (uint32_t i = 0; i < *pPhysicalDeviceGroupCount; i++) {
11500582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                for (uint32_t j = 0; j < pPhysicalDeviceGroupProperties[i].physicalDeviceCount; j++) {
11501582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                    VkPhysicalDevice cur_phys_dev = pPhysicalDeviceGroupProperties[i].physicalDevices[j];
11502582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                    auto &phys_device_state = instance_data->physical_device_map[cur_phys_dev];
11503582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                    phys_device_state.phys_device = cur_phys_dev;
11504582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                    // Init actual features for each physical device
11505582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                    instance_data->dispatch_table.GetPhysicalDeviceFeatures(cur_phys_dev, &phys_device_state.features);
11506582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen                }
11507582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen            }
11508582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        }
11509582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        return result;
11510582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen    } else {
11511582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen        log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, 0, __LINE__,
115129b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                DEVLIMITS_INVALID_INSTANCE, "DL",
115139b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                "Invalid instance (0x%" PRIxLEAST64 ") passed into vkEnumeratePhysicalDeviceGroupsKHX().",
115149b6bedb9061a3ab94386ee9293da1dd43267a680Petr Kraus                HandleToUint64(instance));
11515582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen    }
11516582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen    return VK_ERROR_VALIDATION_FAILED_EXT;
11517582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen}
11518582b6ed09649188d55ed3b6237352caf9f3384a9Mike Weiblen
115196246f8feba03ddc787c31b3daa6a50d4ef01024fMark LobodzinskiVKAPI_ATTR VkResult VKAPI_CALL CreateDescriptorUpdateTemplateKHR(VkDevice device,
115206246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                                 const VkDescriptorUpdateTemplateCreateInfoKHR *pCreateInfo,
115216246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                                 const VkAllocationCallbacks *pAllocator,
115226246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                                 VkDescriptorUpdateTemplateKHR *pDescriptorUpdateTemplate) {
115236246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
11524a538cd4fff983b172362b0bba58f984124481a1cMark Lobodzinski    VkResult result =
11525a538cd4fff983b172362b0bba58f984124481a1cMark Lobodzinski        dev_data->dispatch_table.CreateDescriptorUpdateTemplateKHR(device, pCreateInfo, pAllocator, pDescriptorUpdateTemplate);
115266246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    if (VK_SUCCESS == result) {
115276246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        std::lock_guard<std::mutex> lock(global_lock);
115286246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        // Shadow template createInfo for later updates
11529a538cd4fff983b172362b0bba58f984124481a1cMark Lobodzinski        safe_VkDescriptorUpdateTemplateCreateInfoKHR *local_create_info =
11530a538cd4fff983b172362b0bba58f984124481a1cMark Lobodzinski            new safe_VkDescriptorUpdateTemplateCreateInfoKHR(pCreateInfo);
115316246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        std::unique_ptr<TEMPLATE_STATE> template_state(new TEMPLATE_STATE(*pDescriptorUpdateTemplate, local_create_info));
115326246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski        dev_data->desc_template_map[*pDescriptorUpdateTemplate] = std::move(template_state);
115336246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    }
115346246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    return result;
115356246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski}
115366246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski
115376246f8feba03ddc787c31b3daa6a50d4ef01024fMark LobodzinskiVKAPI_ATTR void VKAPI_CALL DestroyDescriptorUpdateTemplateKHR(VkDevice device,
115386246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                              VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
115396246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                              const VkAllocationCallbacks *pAllocator) {
115406246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
115416246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    std::unique_lock<std::mutex> lock(global_lock);
115426246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    dev_data->desc_template_map.erase(descriptorUpdateTemplate);
115436246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    lock.unlock();
115446246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    dev_data->dispatch_table.DestroyDescriptorUpdateTemplateKHR(device, descriptorUpdateTemplate, pAllocator);
115456246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski}
115466246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski
1154725f3712aed1cebdcb7c92eb25c5f1cc6e5986ac4Mark Lobodzinski// PostCallRecord* handles recording state updates following call down chain to UpdateDescriptorSetsWithTemplate()
1154825f3712aed1cebdcb7c92eb25c5f1cc6e5986ac4Mark Lobodzinskistatic void PostCallRecordUpdateDescriptorSetWithTemplateKHR(layer_data *device_data, VkDescriptorSet descriptorSet,
1154925f3712aed1cebdcb7c92eb25c5f1cc6e5986ac4Mark Lobodzinski                                                             VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
1155025f3712aed1cebdcb7c92eb25c5f1cc6e5986ac4Mark Lobodzinski                                                             const void *pData) {
1155167fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski    auto const template_map_entry = device_data->desc_template_map.find(descriptorUpdateTemplate);
1155267fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski    if (template_map_entry == device_data->desc_template_map.end()) {
1155367fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski        assert(0);
1155467fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski    }
1155567fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski
1155625f3712aed1cebdcb7c92eb25c5f1cc6e5986ac4Mark Lobodzinski    cvdescriptorset::PerformUpdateDescriptorSetsWithTemplateKHR(device_data, descriptorSet, template_map_entry->second, pData);
1155767fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski}
1155867fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski
115596246f8feba03ddc787c31b3daa6a50d4ef01024fMark LobodzinskiVKAPI_ATTR void VKAPI_CALL UpdateDescriptorSetWithTemplateKHR(VkDevice device, VkDescriptorSet descriptorSet,
115606246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                              VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
115616246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                              const void *pData) {
1156267fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
1156367fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski    device_data->dispatch_table.UpdateDescriptorSetWithTemplateKHR(device, descriptorSet, descriptorUpdateTemplate, pData);
1156467fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski
1156567fe2a610e6fc19f5bf11df4b663cef1f6c4e9caMark Lobodzinski    PostCallRecordUpdateDescriptorSetWithTemplateKHR(device_data, descriptorSet, descriptorUpdateTemplate, pData);
115666246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski}
115676246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski
115686246f8feba03ddc787c31b3daa6a50d4ef01024fMark LobodzinskiVKAPI_ATTR void VKAPI_CALL CmdPushDescriptorSetWithTemplateKHR(VkCommandBuffer commandBuffer,
115696246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                               VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
115706246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski                                                               VkPipelineLayout layout, uint32_t set, const void *pData) {
115716246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
115726246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski    dev_data->dispatch_table.CmdPushDescriptorSetWithTemplateKHR(commandBuffer, descriptorUpdateTemplate, layout, set, pData);
115736246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski}
115746246f8feba03ddc787c31b3daa6a50d4ef01024fMark Lobodzinski
115753616276bb0053c612c0a8d223e81ae3808b1b2c4Mark LobodzinskiVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice device, const char *funcName);
115763616276bb0053c612c0a8d223e81ae3808b1b2c4Mark LobodzinskiVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName);
115773616276bb0053c612c0a8d223e81ae3808b1b2c4Mark LobodzinskiVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetInstanceProcAddr(VkInstance instance, const char *funcName);
115783616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski
115793616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski// Map of all APIs to be intercepted by this layer
115803616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinskistatic const std::unordered_map<std::string, void*> name_to_funcptr_map = {
115813616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetInstanceProcAddr", (void*)GetInstanceProcAddr},
115823616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vk_layerGetPhysicalDeviceProcAddr", (void*)GetPhysicalDeviceProcAddr},
115833616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetDeviceProcAddr", (void*)GetDeviceProcAddr},
115843616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateInstance", (void*)CreateInstance},
115853616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateDevice", (void*)CreateDevice},
115863616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkEnumeratePhysicalDevices", (void*)EnumeratePhysicalDevices},
115873616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceQueueFamilyProperties", (void*)GetPhysicalDeviceQueueFamilyProperties},
115883616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyInstance", (void*)DestroyInstance},
115893616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkEnumerateInstanceLayerProperties", (void*)EnumerateInstanceLayerProperties},
115903616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkEnumerateDeviceLayerProperties", (void*)EnumerateDeviceLayerProperties},
115913616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkEnumerateInstanceExtensionProperties", (void*)EnumerateInstanceExtensionProperties},
115923616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkEnumerateDeviceExtensionProperties", (void*)EnumerateDeviceExtensionProperties},
115933616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateDescriptorUpdateTemplateKHR", (void*)CreateDescriptorUpdateTemplateKHR},
115943616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyDescriptorUpdateTemplateKHR", (void*)DestroyDescriptorUpdateTemplateKHR},
115953616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkUpdateDescriptorSetWithTemplateKHR", (void*)UpdateDescriptorSetWithTemplateKHR},
115963616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdPushDescriptorSetWithTemplateKHR", (void*)CmdPushDescriptorSetWithTemplateKHR},
115973616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateSwapchainKHR", (void*)CreateSwapchainKHR},
115983616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroySwapchainKHR", (void*)DestroySwapchainKHR},
115993616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetSwapchainImagesKHR", (void*)GetSwapchainImagesKHR},
116003616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkAcquireNextImageKHR", (void*)AcquireNextImageKHR},
116013616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkQueuePresentKHR", (void*)QueuePresentKHR},
116023616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkQueueSubmit", (void*)QueueSubmit},
116033616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkWaitForFences", (void*)WaitForFences},
116043616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetFenceStatus", (void*)GetFenceStatus},
116053616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkQueueWaitIdle", (void*)QueueWaitIdle},
116063616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDeviceWaitIdle", (void*)DeviceWaitIdle},
116073616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetDeviceQueue", (void*)GetDeviceQueue},
116083616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyDevice", (void*)DestroyDevice},
116093616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyFence", (void*)DestroyFence},
116103616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkResetFences", (void*)ResetFences},
116113616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroySemaphore", (void*)DestroySemaphore},
116123616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyEvent", (void*)DestroyEvent},
116133616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyQueryPool", (void*)DestroyQueryPool},
116143616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyBuffer", (void*)DestroyBuffer},
116153616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyBufferView", (void*)DestroyBufferView},
116163616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyImage", (void*)DestroyImage},
116173616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyImageView", (void*)DestroyImageView},
116183616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyShaderModule", (void*)DestroyShaderModule},
116193616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyPipeline", (void*)DestroyPipeline},
116203616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyPipelineLayout", (void*)DestroyPipelineLayout},
116213616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroySampler", (void*)DestroySampler},
116223616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyDescriptorSetLayout", (void*)DestroyDescriptorSetLayout},
116233616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyDescriptorPool", (void*)DestroyDescriptorPool},
116243616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyFramebuffer", (void*)DestroyFramebuffer},
116253616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyRenderPass", (void*)DestroyRenderPass},
116263616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateBuffer", (void*)CreateBuffer},
116273616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateBufferView", (void*)CreateBufferView},
116283616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateImage", (void*)CreateImage},
116293616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateImageView", (void*)CreateImageView},
116303616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateFence", (void*)CreateFence},
116313616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreatePipelineCache", (void*)CreatePipelineCache},
116323616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyPipelineCache", (void*)DestroyPipelineCache},
116333616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPipelineCacheData", (void*)GetPipelineCacheData},
116343616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkMergePipelineCaches", (void*)MergePipelineCaches},
116353616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateGraphicsPipelines", (void*)CreateGraphicsPipelines},
116363616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateComputePipelines", (void*)CreateComputePipelines},
116373616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateSampler", (void*)CreateSampler},
116383616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateDescriptorSetLayout", (void*)CreateDescriptorSetLayout},
116393616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreatePipelineLayout", (void*)CreatePipelineLayout},
116403616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateDescriptorPool", (void*)CreateDescriptorPool},
116413616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkResetDescriptorPool", (void*)ResetDescriptorPool},
116423616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkAllocateDescriptorSets", (void*)AllocateDescriptorSets},
116433616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkFreeDescriptorSets", (void*)FreeDescriptorSets},
116443616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkUpdateDescriptorSets", (void*)UpdateDescriptorSets},
116453616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateCommandPool", (void*)CreateCommandPool},
116463616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyCommandPool", (void*)DestroyCommandPool},
116473616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkResetCommandPool", (void*)ResetCommandPool},
116483616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateQueryPool", (void*)CreateQueryPool},
116493616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkAllocateCommandBuffers", (void*)AllocateCommandBuffers},
116503616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkFreeCommandBuffers", (void*)FreeCommandBuffers},
116513616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkBeginCommandBuffer", (void*)BeginCommandBuffer},
116523616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkEndCommandBuffer", (void*)EndCommandBuffer},
116533616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkResetCommandBuffer", (void*)ResetCommandBuffer},
116543616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdBindPipeline", (void*)CmdBindPipeline},
116553616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdSetViewport", (void*)CmdSetViewport},
116563616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdSetScissor", (void*)CmdSetScissor},
116573616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdSetLineWidth", (void*)CmdSetLineWidth},
116583616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdSetDepthBias", (void*)CmdSetDepthBias},
116593616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdSetBlendConstants", (void*)CmdSetBlendConstants},
116603616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdSetDepthBounds", (void*)CmdSetDepthBounds},
116613616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdSetStencilCompareMask", (void*)CmdSetStencilCompareMask},
116623616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdSetStencilWriteMask", (void*)CmdSetStencilWriteMask},
116633616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdSetStencilReference", (void*)CmdSetStencilReference},
116643616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdBindDescriptorSets", (void*)CmdBindDescriptorSets},
116653616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdBindVertexBuffers", (void*)CmdBindVertexBuffers},
116663616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdBindIndexBuffer", (void*)CmdBindIndexBuffer},
116673616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdDraw", (void*)CmdDraw},
116683616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdDrawIndexed", (void*)CmdDrawIndexed},
116693616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdDrawIndirect", (void*)CmdDrawIndirect},
116703616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdDrawIndexedIndirect", (void*)CmdDrawIndexedIndirect},
116713616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdDispatch", (void*)CmdDispatch},
116723616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdDispatchIndirect", (void*)CmdDispatchIndirect},
116733616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdCopyBuffer", (void*)CmdCopyBuffer},
116743616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdCopyImage", (void*)CmdCopyImage},
116753616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdBlitImage", (void*)CmdBlitImage},
116763616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdCopyBufferToImage", (void*)CmdCopyBufferToImage},
116773616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdCopyImageToBuffer", (void*)CmdCopyImageToBuffer},
116783616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdUpdateBuffer", (void*)CmdUpdateBuffer},
116793616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdFillBuffer", (void*)CmdFillBuffer},
116803616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdClearColorImage", (void*)CmdClearColorImage},
116813616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdClearDepthStencilImage", (void*)CmdClearDepthStencilImage},
116823616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdClearAttachments", (void*)CmdClearAttachments},
116833616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdResolveImage", (void*)CmdResolveImage},
116843616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetImageSubresourceLayout", (void*)GetImageSubresourceLayout},
116853616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdSetEvent", (void*)CmdSetEvent},
116863616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdResetEvent", (void*)CmdResetEvent},
116873616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdWaitEvents", (void*)CmdWaitEvents},
116883616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdPipelineBarrier", (void*)CmdPipelineBarrier},
116893616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdBeginQuery", (void*)CmdBeginQuery},
116903616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdEndQuery", (void*)CmdEndQuery},
116913616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdResetQueryPool", (void*)CmdResetQueryPool},
116923616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdCopyQueryPoolResults", (void*)CmdCopyQueryPoolResults},
116933616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdPushConstants", (void*)CmdPushConstants},
116943616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdWriteTimestamp", (void*)CmdWriteTimestamp},
116953616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateFramebuffer", (void*)CreateFramebuffer},
116963616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateShaderModule", (void*)CreateShaderModule},
116973616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateRenderPass", (void*)CreateRenderPass},
116983616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdBeginRenderPass", (void*)CmdBeginRenderPass},
116993616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdNextSubpass", (void*)CmdNextSubpass},
117003616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdEndRenderPass", (void*)CmdEndRenderPass},
117013616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCmdExecuteCommands", (void*)CmdExecuteCommands},
117023616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkSetEvent", (void*)SetEvent},
117033616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkMapMemory", (void*)MapMemory},
117043616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkUnmapMemory", (void*)UnmapMemory},
117053616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkFlushMappedMemoryRanges", (void*)FlushMappedMemoryRanges},
117063616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkInvalidateMappedMemoryRanges", (void*)InvalidateMappedMemoryRanges},
117073616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkAllocateMemory", (void*)AllocateMemory},
117083616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkFreeMemory", (void*)FreeMemory},
117093616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkBindBufferMemory", (void*)BindBufferMemory},
117103616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetBufferMemoryRequirements", (void*)GetBufferMemoryRequirements},
117113616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetImageMemoryRequirements", (void*)GetImageMemoryRequirements},
117123616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetQueryPoolResults", (void*)GetQueryPoolResults},
117133616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkBindImageMemory", (void*)BindImageMemory},
117143616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkQueueBindSparse", (void*)QueueBindSparse},
117153616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateSemaphore", (void*)CreateSemaphore},
117163616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateEvent", (void*)CreateEvent},
117173616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#ifdef VK_USE_PLATFORM_ANDROID_KHR
117183616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateAndroidSurfaceKHR", (void*)CreateAndroidSurfaceKHR},
117193616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#endif
117203616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#ifdef VK_USE_PLATFORM_MIR_KHR
117213616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateMirSurfaceKHR", (void*)CreateMirSurfaceKHR},
117223616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceMirPresentationSupportKHR", (void*)GetPhysicalDeviceMirPresentationSupportKHR},
117233616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#endif
117243616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#ifdef VK_USE_PLATFORM_WAYLAND_KHR
117253616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateWaylandSurfaceKHR", (void*)CreateWaylandSurfaceKHR},
117263616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceWaylandPresentationSupportKHR", (void*)GetPhysicalDeviceWaylandPresentationSupportKHR},
117273616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#endif
117283616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#ifdef VK_USE_PLATFORM_WIN32_KHR
117293616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateWin32SurfaceKHR", (void*)CreateWin32SurfaceKHR},
117303616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceWin32PresentationSupportKHR", (void*)GetPhysicalDeviceWin32PresentationSupportKHR},
117313616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#endif
117323616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#ifdef VK_USE_PLATFORM_XCB_KHR
117333616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateXcbSurfaceKHR", (void*)CreateXcbSurfaceKHR},
117343616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceXcbPresentationSupportKHR", (void*)GetPhysicalDeviceXcbPresentationSupportKHR},
117353616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#endif
117363616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#ifdef VK_USE_PLATFORM_XLIB_KHR
117373616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateXlibSurfaceKHR", (void*)CreateXlibSurfaceKHR},
117383616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceXlibPresentationSupportKHR", (void*)GetPhysicalDeviceXlibPresentationSupportKHR},
117393616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski#endif
117403616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateDisplayPlaneSurfaceKHR", (void*)CreateDisplayPlaneSurfaceKHR},
117413616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroySurfaceKHR", (void*)DestroySurfaceKHR},
117423616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceSurfaceCapabilitiesKHR", (void*)GetPhysicalDeviceSurfaceCapabilitiesKHR},
117433616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceSurfaceCapabilities2KHR", (void*)GetPhysicalDeviceSurfaceCapabilities2KHR},
117443616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceSurfaceCapabilities2EXT", (void*)GetPhysicalDeviceSurfaceCapabilities2EXT},
117453616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceSurfaceSupportKHR", (void*)GetPhysicalDeviceSurfaceSupportKHR},
117463616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceSurfacePresentModesKHR", (void*)GetPhysicalDeviceSurfacePresentModesKHR},
117473616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceSurfaceFormatsKHR", (void*)GetPhysicalDeviceSurfaceFormatsKHR},
117483616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceSurfaceFormats2KHR", (void*)GetPhysicalDeviceSurfaceFormats2KHR},
117493616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkGetPhysicalDeviceQueueFamilyProperties2KHR", (void*)GetPhysicalDeviceQueueFamilyProperties2KHR},
117503616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkEnumeratePhysicalDeviceGroupsKHX", (void*)EnumeratePhysicalDeviceGroupsKHX},
117513616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkCreateDebugReportCallbackEXT", (void*)CreateDebugReportCallbackEXT},
117523616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDestroyDebugReportCallbackEXT", (void*)DestroyDebugReportCallbackEXT},
117533616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    {"vkDebugReportMessageEXT", (void*)DebugReportMessageEXT},
117543616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski};
11755b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
117563616276bb0053c612c0a8d223e81ae3808b1b2c4Mark LobodzinskiVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice device, const char *funcName) {
117573616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    assert(device);
117583616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
117595b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
117603616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    // Is API to be intercepted by this layer?
117613616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    const auto &item = name_to_funcptr_map.find(funcName);
117623616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    if (item != name_to_funcptr_map.end()) {
117633616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski        return reinterpret_cast<PFN_vkVoidFunction>(item->second);
117643616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    }
1176509a2f8128f58f032b73d29fab5afd789626562c3Chia-I Wu
117663616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    auto &table = device_data->dispatch_table;
11767cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!table.GetDeviceProcAddr) return nullptr;
117683616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    return table.GetDeviceProcAddr(device, funcName);
117695b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
117705b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis
1177189d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I WuVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetInstanceProcAddr(VkInstance instance, const char *funcName) {
117723616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    instance_layer_data *instance_data;
117733616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    // Is API to be intercepted by this layer?
117743616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    const auto &item = name_to_funcptr_map.find(funcName);
117753616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    if (item != name_to_funcptr_map.end()) {
117763616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski        return reinterpret_cast<PFN_vkVoidFunction>(item->second);
117773616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    }
11778b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
117793616276bb0053c612c0a8d223e81ae3808b1b2c4Mark Lobodzinski    instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
117804a0754042cf090e131e9e769d8a3633c228625beChris Forbes    auto &table = instance_data->dispatch_table;
11781cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!table.GetInstanceProcAddr) return nullptr;
117824a0754042cf090e131e9e769d8a3633c228625beChris Forbes    return table.GetInstanceProcAddr(instance, funcName);
117835b5e7bcfe47d9ed90d0d5edbbe11edf7214a7784Tobin Ehlis}
1178408939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu
11785b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark YoungVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
11786b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    assert(instance);
1178756e14f5c1c3c1cc8e3137bee5c3093d238763a42Tobin Ehlis    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
11788b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11789b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    auto &table = instance_data->dispatch_table;
11790cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski    if (!table.GetPhysicalDeviceProcAddr) return nullptr;
11791b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    return table.GetPhysicalDeviceProcAddr(instance, funcName);
11792b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young}
11793b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11794cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski}  // namespace core_validation
11795d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11796a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu// loader-layer interface v0, just wrappers since there is only a layer
11797d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11798bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
11799bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                      VkExtensionProperties *pProperties) {
11800a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return core_validation::EnumerateInstanceExtensionProperties(pLayerName, pCount, pProperties);
1180108939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu}
1180208939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu
11803bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties(uint32_t *pCount,
11804bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                  VkLayerProperties *pProperties) {
11805a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return core_validation::EnumerateInstanceLayerProperties(pCount, pProperties);
1180608939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu}
1180708939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu
11808bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
11809bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                VkLayerProperties *pProperties) {
11810a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    // the layer command handles VK_NULL_HANDLE just fine internally
11811a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    assert(physicalDevice == VK_NULL_HANDLE);
11812a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    return core_validation::EnumerateDeviceLayerProperties(VK_NULL_HANDLE, pCount, pProperties);
11813d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
11814d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11815d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I WuVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
11816d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu                                                                                    const char *pLayerName, uint32_t *pCount,
11817d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu                                                                                    VkExtensionProperties *pProperties) {
11818a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    // the layer command handles VK_NULL_HANDLE just fine internally
11819a4e71cd8b4e77502943dd894ed95426a25dffbd5Chia-I Wu    assert(physicalDevice == VK_NULL_HANDLE);
11820a8f4a23b1e9c068717eda47cc583a93f447c77e3Chia-I Wu    return core_validation::EnumerateDeviceExtensionProperties(VK_NULL_HANDLE, pLayerName, pCount, pProperties);
11821d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
11822d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11823d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I WuVK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev, const char *funcName) {
1182489d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu    return core_validation::GetDeviceProcAddr(dev, funcName);
11825d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu}
11826d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I Wu
11827d16a2fd05d0b6bd20c7274560c88e37e4b3adefcChia-I WuVK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) {
1182889d6bb8ab0ab38202ecfb3d6e21f60c884cc62e5Chia-I Wu    return core_validation::GetInstanceProcAddr(instance, funcName);
1182908939232d080c94fc7b4c5ad348644928beb1519Chia-I Wu}
11830b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11831bc9caa57c5583dfdf05198e78b78a7cb361da16cMark LobodzinskiVK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_layerGetPhysicalDeviceProcAddr(VkInstance instance,
11832bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski                                                                                           const char *funcName) {
11833b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    return core_validation::GetPhysicalDeviceProcAddr(instance, funcName);
11834b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young}
11835b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11836b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark YoungVK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct) {
11837b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    assert(pVersionStruct != NULL);
11838b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    assert(pVersionStruct->sType == LAYER_NEGOTIATE_INTERFACE_STRUCT);
11839b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11840b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    // Fill in the function pointers if our version is at least capable of having the structure contain them.
11841b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    if (pVersionStruct->loaderLayerInterfaceVersion >= 2) {
11842b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        pVersionStruct->pfnGetInstanceProcAddr = vkGetInstanceProcAddr;
11843b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        pVersionStruct->pfnGetDeviceProcAddr = vkGetDeviceProcAddr;
11844b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        pVersionStruct->pfnGetPhysicalDeviceProcAddr = vk_layerGetPhysicalDeviceProcAddr;
11845b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    }
11846b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11847b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    if (pVersionStruct->loaderLayerInterfaceVersion < CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
11848b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        core_validation::loader_layer_if_version = pVersionStruct->loaderLayerInterfaceVersion;
11849b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    } else if (pVersionStruct->loaderLayerInterfaceVersion > CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
11850b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young        pVersionStruct->loaderLayerInterfaceVersion = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
11851b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    }
11852b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young
11853b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young    return VK_SUCCESS;
11854b5f087aec8b42faee128c5c3dd1cb11b662d85aaMark Young}
11855